Merge pull request #797 from tahoe-lafs/3396.storage-tests-python-3

Make allmydata.test.test_storage run (but not pass!) on Python 3

Fixes ticket:3396
This commit is contained in:
Itamar Turner-Trauring 2020-09-04 14:50:40 -04:00 committed by GitHub
commit e237b37069
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
16 changed files with 75 additions and 68 deletions

0
newsfragments/3396.minor Normal file
View File

View File

@ -2,7 +2,10 @@ import os, stat, time, weakref
from base64 import urlsafe_b64encode from base64 import urlsafe_b64encode
from functools import partial from functools import partial
from errno import ENOENT, EPERM from errno import ENOENT, EPERM
from ConfigParser import NoSectionError try:
from ConfigParser import NoSectionError
except ImportError:
from configparser import NoSectionError
from foolscap.furl import ( from foolscap.furl import (
decode_furl, decode_furl,

View File

@ -1,4 +1,6 @@
"""Directory Node implementation.""" """Directory Node implementation."""
from past.builtins import unicode
import time import time
from zope.interface import implementer from zope.interface import implementer
@ -227,7 +229,7 @@ def pack_children(childrenx, writekey, deep_immutable=False):
return _pack_normalized_children(children, writekey=writekey, deep_immutable=deep_immutable) return _pack_normalized_children(children, writekey=writekey, deep_immutable=deep_immutable)
ZERO_LEN_NETSTR=netstring('') ZERO_LEN_NETSTR=netstring(b'')
def _pack_normalized_children(children, writekey, deep_immutable=False): def _pack_normalized_children(children, writekey, deep_immutable=False):
"""Take a dict that maps: """Take a dict that maps:
children[unicode_nfc_name] = (IFileSystemNode, metadata_dict) children[unicode_nfc_name] = (IFileSystemNode, metadata_dict)

View File

@ -4,7 +4,7 @@ from foolscap.api import eventually
from allmydata.interfaces import NotEnoughSharesError, NoSharesError from allmydata.interfaces import NotEnoughSharesError, NoSharesError
from allmydata.util import log from allmydata.util import log
from allmydata.util.dictutil import DictOfSets from allmydata.util.dictutil import DictOfSets
from common import OVERDUE, COMPLETE, CORRUPT, DEAD, BADSEGNUM, \ from .common import OVERDUE, COMPLETE, CORRUPT, DEAD, BADSEGNUM, \
BadSegmentNumberError BadSegmentNumberError
class SegmentFetcher(object): class SegmentFetcher(object):

View File

@ -5,7 +5,7 @@ from foolscap.api import eventually
from allmydata.util import base32, log from allmydata.util import base32, log
from twisted.internet import reactor from twisted.internet import reactor
from share import Share, CommonShare from .share import Share, CommonShare
def incidentally(res, f, *args, **kwargs): def incidentally(res, f, *args, **kwargs):
"""Add me to a Deferred chain like this: """Add me to a Deferred chain like this:

View File

@ -13,10 +13,10 @@ from allmydata.hashtree import IncompleteHashTree, BadHashError, \
NotEnoughHashesError NotEnoughHashesError
# local imports # local imports
from finder import ShareFinder from .finder import ShareFinder
from fetcher import SegmentFetcher from .fetcher import SegmentFetcher
from segmentation import Segmentation from .segmentation import Segmentation
from common import BadCiphertextHashError from .common import BadCiphertextHashError
class IDownloadStatusHandlingConsumer(Interface): class IDownloadStatusHandlingConsumer(Interface):
def set_download_status_read_event(read_ev): def set_download_status_read_event(read_ev):

View File

@ -9,7 +9,7 @@ from allmydata.util import log
from allmydata.util.spans import overlap from allmydata.util.spans import overlap
from allmydata.interfaces import DownloadStopped from allmydata.interfaces import DownloadStopped
from common import BadSegmentNumberError, WrongSegmentError from .common import BadSegmentNumberError, WrongSegmentError
@implementer(IPushProducer) @implementer(IPushProducer)
class Segmentation(object): class Segmentation(object):

View File

@ -13,7 +13,7 @@ from allmydata.hashtree import IncompleteHashTree, BadHashError, \
from allmydata.immutable.layout import make_write_bucket_proxy from allmydata.immutable.layout import make_write_bucket_proxy
from allmydata.util.observer import EventStreamObserver from allmydata.util.observer import EventStreamObserver
from common import COMPLETE, CORRUPT, DEAD, BADSEGNUM from .common import COMPLETE, CORRUPT, DEAD, BADSEGNUM
class LayoutInvalid(Exception): class LayoutInvalid(Exception):

View File

@ -1,3 +1,5 @@
from past.builtins import long
import os, time, weakref, itertools import os, time, weakref, itertools
from zope.interface import implementer from zope.interface import implementer
from twisted.python import failure from twisted.python import failure
@ -26,7 +28,7 @@ from allmydata.interfaces import IUploadable, IUploader, IUploadResults, \
from allmydata.immutable import layout from allmydata.immutable import layout
from six.moves import cStringIO as StringIO from six.moves import cStringIO as StringIO
from happiness_upload import share_placement, calculate_happiness from .happiness_upload import share_placement, calculate_happiness
from ..util.eliotutil import ( from ..util.eliotutil import (
log_call_deferred, log_call_deferred,

View File

@ -2,12 +2,17 @@
This module contains classes and functions to implement and manage This module contains classes and functions to implement and manage
a node for Tahoe-LAFS. a node for Tahoe-LAFS.
""" """
from past.builtins import unicode
import datetime import datetime
import os.path import os.path
import re import re
import types import types
import errno import errno
import ConfigParser try:
import ConfigParser
except ImportError:
import configparser as ConfigParser
import tempfile import tempfile
from io import BytesIO from io import BytesIO
from base64 import b32decode, b32encode from base64 import b32decode, b32encode
@ -67,7 +72,7 @@ def _common_valid_config():
# Add our application versions to the data that Foolscap's LogPublisher # Add our application versions to the data that Foolscap's LogPublisher
# reports. # reports.
for thing, things_version in get_package_versions().iteritems(): for thing, things_version in get_package_versions().items():
app_versions.add_version(thing, str(things_version)) app_versions.add_version(thing, str(things_version))
# group 1 will be addr (dotted quad string), group 3 if any will be portnum (string) # group 1 will be addr (dotted quad string), group 3 if any will be portnum (string)
@ -272,7 +277,10 @@ class _Config(object):
self.config = configparser self.config = configparser
nickname_utf8 = self.get_config("node", "nickname", "<unspecified>") nickname_utf8 = self.get_config("node", "nickname", "<unspecified>")
self.nickname = nickname_utf8.decode("utf-8") if isinstance(nickname_utf8, bytes): # Python 2
self.nickname = nickname_utf8.decode("utf-8")
else:
self.nickname = nickname_utf8
assert type(self.nickname) is unicode assert type(self.nickname) is unicode
def validate(self, valid_config_sections): def validate(self, valid_config_sections):

View File

@ -30,9 +30,12 @@ the foolscap-based server implemented in src/allmydata/storage/*.py .
import re, time, hashlib import re, time, hashlib
from ConfigParser import ( try:
NoSectionError, from ConfigParser import (
) NoSectionError,
)
except ImportError:
from configparser import NoSectionError
import attr import attr
from zope.interface import ( from zope.interface import (
Attribute, Attribute,
@ -534,11 +537,11 @@ class _NullStorage(object):
which we can't communicate. which we can't communicate.
""" """
nickname = "" nickname = ""
permutation_seed = hashlib.sha256("").digest() permutation_seed = hashlib.sha256(b"").digest()
tubid = hashlib.sha256("").digest() tubid = hashlib.sha256(b"").digest()
storage_server = None storage_server = None
lease_seed = hashlib.sha256("").digest() lease_seed = hashlib.sha256(b"").digest()
name = "<unsupported>" name = "<unsupported>"
longname = "<storage with unsupported protocol>" longname = "<storage with unsupported protocol>"

View File

@ -52,7 +52,6 @@ from twisted.internet.defer import inlineCallbacks, returnValue
from twisted.internet.interfaces import IPullProducer from twisted.internet.interfaces import IPullProducer
from twisted.python import failure from twisted.python import failure
from twisted.python.filepath import FilePath from twisted.python.filepath import FilePath
from twisted.application import service
from twisted.web.error import Error as WebError from twisted.web.error import Error as WebError
from twisted.internet.interfaces import ( from twisted.internet.interfaces import (
IStreamServerEndpointStringParser, IStreamServerEndpointStringParser,
@ -88,6 +87,8 @@ from ..crypto import (
from .eliotutil import ( from .eliotutil import (
EliotLoggedRunTest, EliotLoggedRunTest,
) )
# Backwards compatibility imports:
from .common_py3 import LoggingServiceParent, ShouldFailMixin # noqa: F401
TEST_RSA_KEY_SIZE = 522 TEST_RSA_KEY_SIZE = 522
@ -780,53 +781,8 @@ def create_mutable_filenode(contents, mdmf=False, all_contents=None):
return filenode return filenode
class LoggingServiceParent(service.MultiService):
def log(self, *args, **kwargs):
return log.msg(*args, **kwargs)
TEST_DATA="\x02"*(Uploader.URI_LIT_SIZE_THRESHOLD+1) TEST_DATA="\x02"*(Uploader.URI_LIT_SIZE_THRESHOLD+1)
class ShouldFailMixin(object):
def shouldFail(self, expected_failure, which, substring,
callable, *args, **kwargs):
"""Assert that a function call raises some exception. This is a
Deferred-friendly version of TestCase.assertRaises() .
Suppose you want to verify the following function:
def broken(a, b, c):
if a < 0:
raise TypeError('a must not be negative')
return defer.succeed(b+c)
You can use:
d = self.shouldFail(TypeError, 'test name',
'a must not be negative',
broken, -4, 5, c=12)
in your test method. The 'test name' string will be included in the
error message, if any, because Deferred chains frequently make it
difficult to tell which assertion was tripped.
The substring= argument, if not None, must appear in the 'repr'
of the message wrapped by this Failure, or the test will fail.
"""
assert substring is None or isinstance(substring, str)
d = defer.maybeDeferred(callable, *args, **kwargs)
def done(res):
if isinstance(res, failure.Failure):
res.trap(expected_failure)
if substring:
message = repr(res.value.args[0])
self.failUnless(substring in message,
"%s: substring '%s' not in '%s'"
% (which, substring, message))
else:
self.fail("%s was supposed to raise %s, not get '%s'" %
(which, expected_failure, res))
d.addBoth(done)
return d
class WebErrorMixin(object): class WebErrorMixin(object):
def explain_web_error(self, f): def explain_web_error(self, f):

View File

@ -19,11 +19,13 @@ import time
import signal import signal
from twisted.internet import defer, reactor from twisted.internet import defer, reactor
from twisted.application import service
from twisted.python import failure from twisted.python import failure
from twisted.trial import unittest from twisted.trial import unittest
from ..util.assertutil import precondition from ..util.assertutil import precondition
from ..util.encodingutil import unicode_platform, get_filesystem_encoding from ..util.encodingutil import unicode_platform, get_filesystem_encoding
from ..util import log
class TimezoneMixin(object): class TimezoneMixin(object):
@ -77,6 +79,28 @@ class ShouldFailMixin(object):
def shouldFail(self, expected_failure, which, substring, def shouldFail(self, expected_failure, which, substring,
callable, *args, **kwargs): callable, *args, **kwargs):
"""Assert that a function call raises some exception. This is a
Deferred-friendly version of TestCase.assertRaises() .
Suppose you want to verify the following function:
def broken(a, b, c):
if a < 0:
raise TypeError('a must not be negative')
return defer.succeed(b+c)
You can use:
d = self.shouldFail(TypeError, 'test name',
'a must not be negative',
broken, -4, 5, c=12)
in your test method. The 'test name' string will be included in the
error message, if any, because Deferred chains frequently make it
difficult to tell which assertion was tripped.
The substring= argument, if not None, must appear in the 'repr'
of the message wrapped by this Failure, or the test will fail.
"""
assert substring is None or isinstance(substring, (bytes, unicode)) assert substring is None or isinstance(substring, (bytes, unicode))
d = defer.maybeDeferred(callable, *args, **kwargs) d = defer.maybeDeferred(callable, *args, **kwargs)
def done(res): def done(res):
@ -135,3 +159,9 @@ class FakeCanary(object):
if self.ignore: if self.ignore:
return return
del self.disconnectors[marker] del self.disconnectors[marker]
class LoggingServiceParent(service.MultiService):
def log(self, *args, **kwargs):
return log.msg(*args, **kwargs)

View File

@ -2,6 +2,8 @@
Tools aimed at the interaction between tests and Eliot. Tools aimed at the interaction between tests and Eliot.
""" """
from past.builtins import unicode
__all__ = [ __all__ = [
"RUN_TEST", "RUN_TEST",
"EliotLoggedRunTest", "EliotLoggedRunTest",

View File

@ -30,12 +30,11 @@ from allmydata.mutable.layout import MDMFSlotWriteProxy, MDMFSlotReadProxy, \
VERIFICATION_KEY_SIZE, \ VERIFICATION_KEY_SIZE, \
SHARE_HASH_CHAIN_SIZE SHARE_HASH_CHAIN_SIZE
from allmydata.interfaces import BadWriteEnablerError from allmydata.interfaces import BadWriteEnablerError
from allmydata.test.common import LoggingServiceParent, ShouldFailMixin
from allmydata.test.no_network import NoNetworkServer from allmydata.test.no_network import NoNetworkServer
from allmydata.storage_client import ( from allmydata.storage_client import (
_StorageServer, _StorageServer,
) )
from .common_py3 import FakeCanary from .common_py3 import FakeCanary, LoggingServiceParent, ShouldFailMixin
class FakeStatsProvider(object): class FakeStatsProvider(object):

View File

@ -980,6 +980,8 @@ class CountingDataUploadable(upload.Data):
class SystemTest(SystemTestMixin, RunBinTahoeMixin, unittest.TestCase): class SystemTest(SystemTestMixin, RunBinTahoeMixin, unittest.TestCase):
timeout = 180
def test_connections(self): def test_connections(self):
self.basedir = "system/SystemTest/test_connections" self.basedir = "system/SystemTest/test_connections"
d = self.set_up_nodes() d = self.set_up_nodes()