Hello community,

here is the log from the commit of package python-certbot-dns-digitalocean for 
openSUSE:Factory checked in at 2020-01-03 17:39:01
++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Comparing /work/SRC/openSUSE:Factory/python-certbot-dns-digitalocean (Old)
 and      /work/SRC/openSUSE:Factory/.python-certbot-dns-digitalocean.new.6675 
(New)
++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++

Package is "python-certbot-dns-digitalocean"

Fri Jan  3 17:39:01 2020 rev:14 rq:760652 version:1.0.0

Changes:
--------
--- 
/work/SRC/openSUSE:Factory/python-certbot-dns-digitalocean/python-certbot-dns-digitalocean.changes
  2019-11-15 00:23:52.087875724 +0100
+++ 
/work/SRC/openSUSE:Factory/.python-certbot-dns-digitalocean.new.6675/python-certbot-dns-digitalocean.changes
        2020-01-03 17:39:18.251367116 +0100
@@ -1,0 +2,6 @@
+Fri Jan  3 11:48:56 UTC 2020 - Marketa Calabkova <[email protected]>
+
+- update to version 1.0.0
+  * sync with main certbot package
+
+-------------------------------------------------------------------

Old:
----
  certbot-dns-digitalocean-0.40.1.tar.gz

New:
----
  certbot-dns-digitalocean-1.0.0.tar.gz

++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++

Other differences:
------------------
++++++ python-certbot-dns-digitalocean.spec ++++++
--- /var/tmp/diff_new_pack.A9utVB/_old  2020-01-03 17:39:19.275367641 +0100
+++ /var/tmp/diff_new_pack.A9utVB/_new  2020-01-03 17:39:19.275367641 +0100
@@ -1,7 +1,7 @@
 #
 # spec file for package python-certbot-dns-digitalocean
 #
-# Copyright (c) 2019 SUSE LLC.
+# Copyright (c) 2020 SUSE LLC
 #
 # All modifications and additions to the file contributed by third parties
 # remain the property of their copyright owners, unless otherwise agreed
@@ -18,23 +18,22 @@
 
 %{?!python_module:%define python_module() python-%{**} python3-%{**}}
 Name:           python-certbot-dns-digitalocean
-Version:        0.40.1
+Version:        1.0.0
 Release:        0
 Summary:        DigitalOcean Authenticator plugin for Certbot
 License:        Apache-2.0
 URL:            https://github.com/certbot/certbot
 Source:         
https://files.pythonhosted.org/packages/source/c/certbot-dns-digitalocean/certbot-dns-digitalocean-%{version}.tar.gz
-BuildRequires:  %{python_module certbot >= 0.34.0}
-BuildRequires:  %{python_module digitalocean}
-BuildRequires:  %{python_module dns-lexicon >= 2.2.1}
+BuildRequires:  %{python_module certbot >= 1.0.0}
+BuildRequires:  %{python_module digitalocean >= 1.11}
 BuildRequires:  %{python_module mock}
+BuildRequires:  %{python_module pytest}
 BuildRequires:  %{python_module setuptools}
 BuildRequires:  fdupes
 BuildRequires:  python-rpm-macros
 Requires:       python-acme >= 0.29.0
-Requires:       python-certbot >= 0.34.0
-Requires:       python-digitalocean
-Requires:       python-dns-lexicon >= 2.2.1
+Requires:       python-certbot >= 1.0.0
+Requires:       python-digitalocean >= 1.11
 Requires:       python-six
 Requires:       python-zope.interface
 BuildArch:      noarch

++++++ certbot-dns-digitalocean-0.40.1.tar.gz -> 
certbot-dns-digitalocean-1.0.0.tar.gz ++++++
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/certbot-dns-digitalocean-0.40.1/MANIFEST.in 
new/certbot-dns-digitalocean-1.0.0/MANIFEST.in
--- old/certbot-dns-digitalocean-0.40.1/MANIFEST.in     2019-11-06 
03:24:51.000000000 +0100
+++ new/certbot-dns-digitalocean-1.0.0/MANIFEST.in      2019-12-03 
18:20:30.000000000 +0100
@@ -1,3 +1,6 @@
 include LICENSE.txt
 include README.rst
 recursive-include docs *
+recursive-include tests *
+global-exclude __pycache__
+global-exclude *.py[cod]
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/certbot-dns-digitalocean-0.40.1/PKG-INFO 
new/certbot-dns-digitalocean-1.0.0/PKG-INFO
--- old/certbot-dns-digitalocean-0.40.1/PKG-INFO        2019-11-06 
03:25:05.000000000 +0100
+++ new/certbot-dns-digitalocean-1.0.0/PKG-INFO 2019-12-03 18:20:54.000000000 
+0100
@@ -1,6 +1,6 @@
 Metadata-Version: 2.1
 Name: certbot-dns-digitalocean
-Version: 0.40.1
+Version: 1.0.0
 Summary: DigitalOcean DNS Authenticator plugin for Certbot
 Home-page: https://github.com/certbot/certbot
 Author: Certbot Project
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' 
old/certbot-dns-digitalocean-0.40.1/certbot_dns_digitalocean/_internal/__init__.py
 
new/certbot-dns-digitalocean-1.0.0/certbot_dns_digitalocean/_internal/__init__.py
--- 
old/certbot-dns-digitalocean-0.40.1/certbot_dns_digitalocean/_internal/__init__.py
  1970-01-01 01:00:00.000000000 +0100
+++ 
new/certbot-dns-digitalocean-1.0.0/certbot_dns_digitalocean/_internal/__init__.py
   2019-12-03 18:20:30.000000000 +0100
@@ -0,0 +1 @@
+"""Internal implementation of `~certbot_dns_digitalocean.dns_digitalocean` 
plugin."""
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' 
old/certbot-dns-digitalocean-0.40.1/certbot_dns_digitalocean/_internal/dns_digitalocean.py
 
new/certbot-dns-digitalocean-1.0.0/certbot_dns_digitalocean/_internal/dns_digitalocean.py
--- 
old/certbot-dns-digitalocean-0.40.1/certbot_dns_digitalocean/_internal/dns_digitalocean.py
  1970-01-01 01:00:00.000000000 +0100
+++ 
new/certbot-dns-digitalocean-1.0.0/certbot_dns_digitalocean/_internal/dns_digitalocean.py
   2019-12-03 18:20:30.000000000 +0100
@@ -0,0 +1,168 @@
+"""DNS Authenticator for DigitalOcean."""
+import logging
+
+import digitalocean
+import zope.interface
+
+from certbot import errors
+from certbot import interfaces
+from certbot.plugins import dns_common
+
+logger = logging.getLogger(__name__)
+
+
[email protected](interfaces.IAuthenticator)
[email protected](interfaces.IPluginFactory)
+class Authenticator(dns_common.DNSAuthenticator):
+    """DNS Authenticator for DigitalOcean
+
+    This Authenticator uses the DigitalOcean API to fulfill a dns-01 challenge.
+    """
+
+    description = 'Obtain certs using a DNS TXT record (if you are using 
DigitalOcean for DNS).'
+
+    def __init__(self, *args, **kwargs):
+        super(Authenticator, self).__init__(*args, **kwargs)
+        self.credentials = None
+
+    @classmethod
+    def add_parser_arguments(cls, add):  # pylint: disable=arguments-differ
+        super(Authenticator, cls).add_parser_arguments(add)
+        add('credentials', help='DigitalOcean credentials INI file.')
+
+    def more_info(self):  # pylint: disable=missing-docstring,no-self-use
+        return 'This plugin configures a DNS TXT record to respond to a dns-01 
challenge using ' + \
+               'the DigitalOcean API.'
+
+    def _setup_credentials(self):
+        self.credentials = self._configure_credentials(
+            'credentials',
+            'DigitalOcean credentials INI file',
+            {
+                'token': 'API token for DigitalOcean account'
+            }
+        )
+
+    def _perform(self, domain, validation_name, validation):
+        self._get_digitalocean_client().add_txt_record(domain, 
validation_name, validation)
+
+    def _cleanup(self, domain, validation_name, validation):
+        self._get_digitalocean_client().del_txt_record(domain, 
validation_name, validation)
+
+    def _get_digitalocean_client(self):
+        return _DigitalOceanClient(self.credentials.conf('token'))
+
+
+class _DigitalOceanClient(object):
+    """
+    Encapsulates all communication with the DigitalOcean API.
+    """
+
+    def __init__(self, token):
+        self.manager = digitalocean.Manager(token=token)
+
+    def add_txt_record(self, domain_name, record_name, record_content):
+        """
+        Add a TXT record using the supplied information.
+
+        :param str domain_name: The domain to use to associate the record with.
+        :param str record_name: The record name (typically beginning with 
'_acme-challenge.').
+        :param str record_content: The record content (typically the challenge 
validation).
+        :raises certbot.errors.PluginError: if an error occurs communicating 
with the DigitalOcean
+                                            API
+        """
+
+        try:
+            domain = self._find_domain(domain_name)
+        except digitalocean.Error as e:
+            hint = None
+
+            if str(e).startswith("Unable to authenticate"):
+                hint = 'Did you provide a valid API token?'
+
+            logger.debug('Error finding domain using the DigitalOcean API: 
%s', e)
+            raise errors.PluginError('Error finding domain using the 
DigitalOcean API: {0}{1}'
+                                     .format(e, ' ({0})'.format(hint) if hint 
else ''))
+
+        try:
+            result = domain.create_new_domain_record(
+                type='TXT',
+                name=self._compute_record_name(domain, record_name),
+                data=record_content)
+
+            record_id = result['domain_record']['id']
+
+            logger.debug('Successfully added TXT record with id: %d', 
record_id)
+        except digitalocean.Error as e:
+            logger.debug('Error adding TXT record using the DigitalOcean API: 
%s', e)
+            raise errors.PluginError('Error adding TXT record using the 
DigitalOcean API: {0}'
+                                     .format(e))
+
+    def del_txt_record(self, domain_name, record_name, record_content):
+        """
+        Delete a TXT record using the supplied information.
+
+        Note that both the record's name and content are used to ensure that 
similar records
+        created concurrently (e.g., due to concurrent invocations of this 
plugin) are not deleted.
+
+        Failures are logged, but not raised.
+
+        :param str domain_name: The domain to use to associate the record with.
+        :param str record_name: The record name (typically beginning with 
'_acme-challenge.').
+        :param str record_content: The record content (typically the challenge 
validation).
+        """
+
+        try:
+            domain = self._find_domain(domain_name)
+        except digitalocean.Error as e:
+            logger.debug('Error finding domain using the DigitalOcean API: 
%s', e)
+            return
+
+        try:
+            domain_records = domain.get_records()
+
+            matching_records = [record for record in domain_records
+                                if record.type == 'TXT'
+                                and record.name == 
self._compute_record_name(domain, record_name)
+                                and record.data == record_content]
+        except digitalocean.Error as e:
+            logger.debug('Error getting DNS records using the DigitalOcean 
API: %s', e)
+            return
+
+        for record in matching_records:
+            try:
+                logger.debug('Removing TXT record with id: %s', record.id)
+                record.destroy()
+            except digitalocean.Error as e:
+                logger.warning('Error deleting TXT record %s using the 
DigitalOcean API: %s',
+                            record.id, e)
+
+    def _find_domain(self, domain_name):
+        """
+        Find the domain object for a given domain name.
+
+        :param str domain_name: The domain name for which to find the 
corresponding Domain.
+        :returns: The Domain, if found.
+        :rtype: `~digitalocean.Domain`
+        :raises certbot.errors.PluginError: if no matching Domain is found.
+        """
+
+        domain_name_guesses = dns_common.base_domain_name_guesses(domain_name)
+
+        domains = self.manager.get_all_domains()
+
+        for guess in domain_name_guesses:
+            matches = [domain for domain in domains if domain.name == guess]
+
+            if matches:
+                domain = matches[0]
+                logger.debug('Found base domain for %s using name %s', 
domain_name, guess)
+                return domain
+
+        raise errors.PluginError('Unable to determine base domain for {0} 
using names: {1}.'
+                                 .format(domain_name, domain_name_guesses))
+
+    @staticmethod
+    def _compute_record_name(domain, full_record_name):
+        # The domain, from DigitalOcean's point of view, is automatically 
appended.
+        return full_record_name.rpartition("." + domain.name)[0]
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' 
old/certbot-dns-digitalocean-0.40.1/certbot_dns_digitalocean/dns_digitalocean.py
 new/certbot-dns-digitalocean-1.0.0/certbot_dns_digitalocean/dns_digitalocean.py
--- 
old/certbot-dns-digitalocean-0.40.1/certbot_dns_digitalocean/dns_digitalocean.py
    2019-11-06 03:24:51.000000000 +0100
+++ 
new/certbot-dns-digitalocean-1.0.0/certbot_dns_digitalocean/dns_digitalocean.py 
    1970-01-01 01:00:00.000000000 +0100
@@ -1,168 +0,0 @@
-"""DNS Authenticator for DigitalOcean."""
-import logging
-
-import digitalocean
-import zope.interface
-
-from certbot import errors
-from certbot import interfaces
-from certbot.plugins import dns_common
-
-logger = logging.getLogger(__name__)
-
-
[email protected](interfaces.IAuthenticator)
[email protected](interfaces.IPluginFactory)
-class Authenticator(dns_common.DNSAuthenticator):
-    """DNS Authenticator for DigitalOcean
-
-    This Authenticator uses the DigitalOcean API to fulfill a dns-01 challenge.
-    """
-
-    description = 'Obtain certs using a DNS TXT record (if you are using 
DigitalOcean for DNS).'
-
-    def __init__(self, *args, **kwargs):
-        super(Authenticator, self).__init__(*args, **kwargs)
-        self.credentials = None
-
-    @classmethod
-    def add_parser_arguments(cls, add):  # pylint: disable=arguments-differ
-        super(Authenticator, cls).add_parser_arguments(add)
-        add('credentials', help='DigitalOcean credentials INI file.')
-
-    def more_info(self):  # pylint: disable=missing-docstring,no-self-use
-        return 'This plugin configures a DNS TXT record to respond to a dns-01 
challenge using ' + \
-               'the DigitalOcean API.'
-
-    def _setup_credentials(self):
-        self.credentials = self._configure_credentials(
-            'credentials',
-            'DigitalOcean credentials INI file',
-            {
-                'token': 'API token for DigitalOcean account'
-            }
-        )
-
-    def _perform(self, domain, validation_name, validation):
-        self._get_digitalocean_client().add_txt_record(domain, 
validation_name, validation)
-
-    def _cleanup(self, domain, validation_name, validation):
-        self._get_digitalocean_client().del_txt_record(domain, 
validation_name, validation)
-
-    def _get_digitalocean_client(self):
-        return _DigitalOceanClient(self.credentials.conf('token'))
-
-
-class _DigitalOceanClient(object):
-    """
-    Encapsulates all communication with the DigitalOcean API.
-    """
-
-    def __init__(self, token):
-        self.manager = digitalocean.Manager(token=token)
-
-    def add_txt_record(self, domain_name, record_name, record_content):
-        """
-        Add a TXT record using the supplied information.
-
-        :param str domain_name: The domain to use to associate the record with.
-        :param str record_name: The record name (typically beginning with 
'_acme-challenge.').
-        :param str record_content: The record content (typically the challenge 
validation).
-        :raises certbot.errors.PluginError: if an error occurs communicating 
with the DigitalOcean
-                                            API
-        """
-
-        try:
-            domain = self._find_domain(domain_name)
-        except digitalocean.Error as e:
-            hint = None
-
-            if str(e).startswith("Unable to authenticate"):
-                hint = 'Did you provide a valid API token?'
-
-            logger.debug('Error finding domain using the DigitalOcean API: 
%s', e)
-            raise errors.PluginError('Error finding domain using the 
DigitalOcean API: {0}{1}'
-                                     .format(e, ' ({0})'.format(hint) if hint 
else ''))
-
-        try:
-            result = domain.create_new_domain_record(
-                type='TXT',
-                name=self._compute_record_name(domain, record_name),
-                data=record_content)
-
-            record_id = result['domain_record']['id']
-
-            logger.debug('Successfully added TXT record with id: %d', 
record_id)
-        except digitalocean.Error as e:
-            logger.debug('Error adding TXT record using the DigitalOcean API: 
%s', e)
-            raise errors.PluginError('Error adding TXT record using the 
DigitalOcean API: {0}'
-                                     .format(e))
-
-    def del_txt_record(self, domain_name, record_name, record_content):
-        """
-        Delete a TXT record using the supplied information.
-
-        Note that both the record's name and content are used to ensure that 
similar records
-        created concurrently (e.g., due to concurrent invocations of this 
plugin) are not deleted.
-
-        Failures are logged, but not raised.
-
-        :param str domain_name: The domain to use to associate the record with.
-        :param str record_name: The record name (typically beginning with 
'_acme-challenge.').
-        :param str record_content: The record content (typically the challenge 
validation).
-        """
-
-        try:
-            domain = self._find_domain(domain_name)
-        except digitalocean.Error as e:
-            logger.debug('Error finding domain using the DigitalOcean API: 
%s', e)
-            return
-
-        try:
-            domain_records = domain.get_records()
-
-            matching_records = [record for record in domain_records
-                                if record.type == 'TXT'
-                                and record.name == 
self._compute_record_name(domain, record_name)
-                                and record.data == record_content]
-        except digitalocean.Error as e:
-            logger.debug('Error getting DNS records using the DigitalOcean 
API: %s', e)
-            return
-
-        for record in matching_records:
-            try:
-                logger.debug('Removing TXT record with id: %s', record.id)
-                record.destroy()
-            except digitalocean.Error as e:
-                logger.warning('Error deleting TXT record %s using the 
DigitalOcean API: %s',
-                            record.id, e)
-
-    def _find_domain(self, domain_name):
-        """
-        Find the domain object for a given domain name.
-
-        :param str domain_name: The domain name for which to find the 
corresponding Domain.
-        :returns: The Domain, if found.
-        :rtype: `~digitalocean.Domain`
-        :raises certbot.errors.PluginError: if no matching Domain is found.
-        """
-
-        domain_name_guesses = dns_common.base_domain_name_guesses(domain_name)
-
-        domains = self.manager.get_all_domains()
-
-        for guess in domain_name_guesses:
-            matches = [domain for domain in domains if domain.name == guess]
-
-            if matches:
-                domain = matches[0]
-                logger.debug('Found base domain for %s using name %s', 
domain_name, guess)
-                return domain
-
-        raise errors.PluginError('Unable to determine base domain for {0} 
using names: {1}.'
-                                 .format(domain_name, domain_name_guesses))
-
-    @staticmethod
-    def _compute_record_name(domain, full_record_name):
-        # The domain, from DigitalOcean's point of view, is automatically 
appended.
-        return full_record_name.rpartition("." + domain.name)[0]
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' 
old/certbot-dns-digitalocean-0.40.1/certbot_dns_digitalocean/dns_digitalocean_test.py
 
new/certbot-dns-digitalocean-1.0.0/certbot_dns_digitalocean/dns_digitalocean_test.py
--- 
old/certbot-dns-digitalocean-0.40.1/certbot_dns_digitalocean/dns_digitalocean_test.py
       2019-11-06 03:24:51.000000000 +0100
+++ 
new/certbot-dns-digitalocean-1.0.0/certbot_dns_digitalocean/dns_digitalocean_test.py
        1970-01-01 01:00:00.000000000 +0100
@@ -1,171 +0,0 @@
-"""Tests for certbot_dns_digitalocean.dns_digitalocean."""
-
-import unittest
-
-import digitalocean
-import mock
-
-from certbot import errors
-from certbot.compat import os
-from certbot.plugins import dns_test_common
-from certbot.plugins.dns_test_common import DOMAIN
-from certbot.tests import util as test_util
-
-API_ERROR = digitalocean.DataReadError()
-TOKEN = 'a-token'
-
-
-class AuthenticatorTest(test_util.TempDirTestCase, 
dns_test_common.BaseAuthenticatorTest):
-
-    def setUp(self):
-        from certbot_dns_digitalocean.dns_digitalocean import Authenticator
-
-        super(AuthenticatorTest, self).setUp()
-
-        path = os.path.join(self.tempdir, 'file.ini')
-        dns_test_common.write({"digitalocean_token": TOKEN}, path)
-
-        self.config = mock.MagicMock(digitalocean_credentials=path,
-                                     digitalocean_propagation_seconds=0)  # 
don't wait during tests
-
-        self.auth = Authenticator(self.config, "digitalocean")
-
-        self.mock_client = mock.MagicMock()
-        # _get_digitalocean_client | pylint: disable=protected-access
-        self.auth._get_digitalocean_client = 
mock.MagicMock(return_value=self.mock_client)
-
-    def test_perform(self):
-        self.auth.perform([self.achall])
-
-        expected = [mock.call.add_txt_record(DOMAIN, 
'_acme-challenge.'+DOMAIN, mock.ANY)]
-        self.assertEqual(expected, self.mock_client.mock_calls)
-
-    def test_cleanup(self):
-        # _attempt_cleanup | pylint: disable=protected-access
-        self.auth._attempt_cleanup = True
-        self.auth.cleanup([self.achall])
-
-        expected = [mock.call.del_txt_record(DOMAIN, 
'_acme-challenge.'+DOMAIN, mock.ANY)]
-        self.assertEqual(expected, self.mock_client.mock_calls)
-
-
-class DigitalOceanClientTest(unittest.TestCase):
-
-    id_num = 1
-    record_prefix = "_acme-challenge"
-    record_name = record_prefix + "." + DOMAIN
-    record_content = "bar"
-
-    def setUp(self):
-        from certbot_dns_digitalocean.dns_digitalocean import 
_DigitalOceanClient
-
-        self.digitalocean_client = _DigitalOceanClient(TOKEN)
-
-        self.manager = mock.MagicMock()
-        self.digitalocean_client.manager = self.manager
-
-    def test_add_txt_record(self):
-        wrong_domain_mock = mock.MagicMock()
-        wrong_domain_mock.name = "other.invalid"
-        wrong_domain_mock.create_new_domain_record.side_effect = 
AssertionError('Wrong Domain')
-
-        domain_mock = mock.MagicMock()
-        domain_mock.name = DOMAIN
-        domain_mock.create_new_domain_record.return_value = {'domain_record': 
{'id': self.id_num}}
-
-        self.manager.get_all_domains.return_value = [wrong_domain_mock, 
domain_mock]
-
-        self.digitalocean_client.add_txt_record(DOMAIN, self.record_name, 
self.record_content)
-
-        domain_mock.create_new_domain_record.assert_called_with(type='TXT',
-                                                                
name=self.record_prefix,
-                                                                
data=self.record_content)
-
-    def test_add_txt_record_fail_to_find_domain(self):
-        self.manager.get_all_domains.return_value = []
-
-        self.assertRaises(errors.PluginError,
-                          self.digitalocean_client.add_txt_record,
-                          DOMAIN, self.record_name, self.record_content)
-
-    def test_add_txt_record_error_finding_domain(self):
-        self.manager.get_all_domains.side_effect = API_ERROR
-
-        self.assertRaises(errors.PluginError,
-                          self.digitalocean_client.add_txt_record,
-                          DOMAIN, self.record_name, self.record_content)
-
-    def test_add_txt_record_error_creating_record(self):
-        domain_mock = mock.MagicMock()
-        domain_mock.name = DOMAIN
-        domain_mock.create_new_domain_record.side_effect = API_ERROR
-
-        self.manager.get_all_domains.return_value = [domain_mock]
-
-        self.assertRaises(errors.PluginError,
-                          self.digitalocean_client.add_txt_record,
-                          DOMAIN, self.record_name, self.record_content)
-
-    def test_del_txt_record(self):
-        first_record_mock = mock.MagicMock()
-        first_record_mock.type = 'TXT'
-        first_record_mock.name = "DIFFERENT"
-        first_record_mock.data = self.record_content
-
-        correct_record_mock = mock.MagicMock()
-        correct_record_mock.type = 'TXT'
-        correct_record_mock.name = self.record_prefix
-        correct_record_mock.data = self.record_content
-
-        last_record_mock = mock.MagicMock()
-        last_record_mock.type = 'TXT'
-        last_record_mock.name = self.record_prefix
-        last_record_mock.data = "DIFFERENT"
-
-        domain_mock = mock.MagicMock()
-        domain_mock.name = DOMAIN
-        domain_mock.get_records.return_value = [first_record_mock,
-                                                correct_record_mock,
-                                                last_record_mock]
-
-        self.manager.get_all_domains.return_value = [domain_mock]
-
-        self.digitalocean_client.del_txt_record(DOMAIN, self.record_name, 
self.record_content)
-
-        self.assertTrue(correct_record_mock.destroy.called)
-
-        self.assertFalse(first_record_mock.destroy.call_args_list)
-        self.assertFalse(last_record_mock.destroy.call_args_list)
-
-    def test_del_txt_record_error_finding_domain(self):
-        self.manager.get_all_domains.side_effect = API_ERROR
-
-        self.digitalocean_client.del_txt_record(DOMAIN, self.record_name, 
self.record_content)
-
-    def test_del_txt_record_error_finding_record(self):
-        domain_mock = mock.MagicMock()
-        domain_mock.name = DOMAIN
-        domain_mock.get_records.side_effect = API_ERROR
-
-        self.manager.get_all_domains.return_value = [domain_mock]
-
-        self.digitalocean_client.del_txt_record(DOMAIN, self.record_name, 
self.record_content)
-
-    def test_del_txt_record_error_deleting_record(self):
-        record_mock = mock.MagicMock()
-        record_mock.type = 'TXT'
-        record_mock.name = self.record_prefix
-        record_mock.data = self.record_content
-        record_mock.destroy.side_effect = API_ERROR
-
-        domain_mock = mock.MagicMock()
-        domain_mock.name = DOMAIN
-        domain_mock.get_records.return_value = [record_mock]
-
-        self.manager.get_all_domains.return_value = [domain_mock]
-
-        self.digitalocean_client.del_txt_record(DOMAIN, self.record_name, 
self.record_content)
-
-
-if __name__ == "__main__":
-    unittest.main()  # pragma: no cover
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' 
old/certbot-dns-digitalocean-0.40.1/certbot_dns_digitalocean.egg-info/PKG-INFO 
new/certbot-dns-digitalocean-1.0.0/certbot_dns_digitalocean.egg-info/PKG-INFO
--- 
old/certbot-dns-digitalocean-0.40.1/certbot_dns_digitalocean.egg-info/PKG-INFO  
    2019-11-06 03:25:05.000000000 +0100
+++ 
new/certbot-dns-digitalocean-1.0.0/certbot_dns_digitalocean.egg-info/PKG-INFO   
    2019-12-03 18:20:54.000000000 +0100
@@ -1,6 +1,6 @@
 Metadata-Version: 2.1
 Name: certbot-dns-digitalocean
-Version: 0.40.1
+Version: 1.0.0
 Summary: DigitalOcean DNS Authenticator plugin for Certbot
 Home-page: https://github.com/certbot/certbot
 Author: Certbot Project
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' 
old/certbot-dns-digitalocean-0.40.1/certbot_dns_digitalocean.egg-info/SOURCES.txt
 
new/certbot-dns-digitalocean-1.0.0/certbot_dns_digitalocean.egg-info/SOURCES.txt
--- 
old/certbot-dns-digitalocean-0.40.1/certbot_dns_digitalocean.egg-info/SOURCES.txt
   2019-11-06 03:25:05.000000000 +0100
+++ 
new/certbot-dns-digitalocean-1.0.0/certbot_dns_digitalocean.egg-info/SOURCES.txt
    2019-12-03 18:20:54.000000000 +0100
@@ -4,18 +4,18 @@
 setup.cfg
 setup.py
 certbot_dns_digitalocean/__init__.py
-certbot_dns_digitalocean/dns_digitalocean.py
-certbot_dns_digitalocean/dns_digitalocean_test.py
 certbot_dns_digitalocean.egg-info/PKG-INFO
 certbot_dns_digitalocean.egg-info/SOURCES.txt
 certbot_dns_digitalocean.egg-info/dependency_links.txt
 certbot_dns_digitalocean.egg-info/entry_points.txt
 certbot_dns_digitalocean.egg-info/requires.txt
 certbot_dns_digitalocean.egg-info/top_level.txt
+certbot_dns_digitalocean/_internal/__init__.py
+certbot_dns_digitalocean/_internal/dns_digitalocean.py
 docs/.gitignore
 docs/Makefile
 docs/api.rst
 docs/conf.py
 docs/index.rst
 docs/make.bat
-docs/api/dns_digitalocean.rst
\ No newline at end of file
+tests/dns_digitalocean_test.py
\ No newline at end of file
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' 
old/certbot-dns-digitalocean-0.40.1/certbot_dns_digitalocean.egg-info/entry_points.txt
 
new/certbot-dns-digitalocean-1.0.0/certbot_dns_digitalocean.egg-info/entry_points.txt
--- 
old/certbot-dns-digitalocean-0.40.1/certbot_dns_digitalocean.egg-info/entry_points.txt
      2019-11-06 03:25:05.000000000 +0100
+++ 
new/certbot-dns-digitalocean-1.0.0/certbot_dns_digitalocean.egg-info/entry_points.txt
       2019-12-03 18:20:54.000000000 +0100
@@ -1,3 +1,3 @@
 [certbot.plugins]
-dns-digitalocean = certbot_dns_digitalocean.dns_digitalocean:Authenticator
+dns-digitalocean = 
certbot_dns_digitalocean._internal.dns_digitalocean:Authenticator
 
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' 
old/certbot-dns-digitalocean-0.40.1/docs/api/dns_digitalocean.rst 
new/certbot-dns-digitalocean-1.0.0/docs/api/dns_digitalocean.rst
--- old/certbot-dns-digitalocean-0.40.1/docs/api/dns_digitalocean.rst   
2019-11-06 03:24:51.000000000 +0100
+++ new/certbot-dns-digitalocean-1.0.0/docs/api/dns_digitalocean.rst    
1970-01-01 01:00:00.000000000 +0100
@@ -1,5 +0,0 @@
-:mod:`certbot_dns_digitalocean.dns_digitalocean`
-------------------------------------------------
-
-.. automodule:: certbot_dns_digitalocean.dns_digitalocean
-   :members:
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/certbot-dns-digitalocean-0.40.1/docs/api.rst 
new/certbot-dns-digitalocean-1.0.0/docs/api.rst
--- old/certbot-dns-digitalocean-0.40.1/docs/api.rst    2019-11-06 
03:24:51.000000000 +0100
+++ new/certbot-dns-digitalocean-1.0.0/docs/api.rst     2019-12-03 
18:20:30.000000000 +0100
@@ -2,7 +2,4 @@
 API Documentation
 =================
 
-.. toctree::
-   :glob:
-
-   api/**
+Certbot plugins implement the Certbot plugins API, and do not otherwise have 
an external API.
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/certbot-dns-digitalocean-0.40.1/setup.py 
new/certbot-dns-digitalocean-1.0.0/setup.py
--- old/certbot-dns-digitalocean-0.40.1/setup.py        2019-11-06 
03:24:52.000000000 +0100
+++ new/certbot-dns-digitalocean-1.0.0/setup.py 2019-12-03 18:20:32.000000000 
+0100
@@ -1,8 +1,10 @@
 from setuptools import setup
 from setuptools import find_packages
+from setuptools.command.test import test as TestCommand
+import sys
 
 
-version = '0.40.1'
+version = '1.0.0'
 
 # Remember to update local-oldest-requirements.txt when changing the minimum
 # acme/certbot version.
@@ -21,6 +23,20 @@
     'sphinx_rtd_theme',
 ]
 
+class PyTest(TestCommand):
+    user_options = []
+
+    def initialize_options(self):
+        TestCommand.initialize_options(self)
+        self.pytest_args = ''
+
+    def run_tests(self):
+        import shlex
+        # import here, cause outside the eggs aren't loaded
+        import pytest
+        errno = pytest.main(shlex.split(self.pytest_args))
+        sys.exit(errno)
+
 setup(
     name='certbot-dns-digitalocean',
     version=version,
@@ -61,8 +77,10 @@
     },
     entry_points={
         'certbot.plugins': [
-            'dns-digitalocean = 
certbot_dns_digitalocean.dns_digitalocean:Authenticator',
+            'dns-digitalocean = 
certbot_dns_digitalocean._internal.dns_digitalocean:Authenticator',
         ],
     },
+    tests_require=["pytest"],
     test_suite='certbot_dns_digitalocean',
+    cmdclass={"test": PyTest},
 )
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' 
old/certbot-dns-digitalocean-0.40.1/tests/dns_digitalocean_test.py 
new/certbot-dns-digitalocean-1.0.0/tests/dns_digitalocean_test.py
--- old/certbot-dns-digitalocean-0.40.1/tests/dns_digitalocean_test.py  
1970-01-01 01:00:00.000000000 +0100
+++ new/certbot-dns-digitalocean-1.0.0/tests/dns_digitalocean_test.py   
2019-12-03 18:20:30.000000000 +0100
@@ -0,0 +1,171 @@
+"""Tests for certbot_dns_digitalocean._internal.dns_digitalocean."""
+
+import unittest
+
+import digitalocean
+import mock
+
+from certbot import errors
+from certbot.compat import os
+from certbot.plugins import dns_test_common
+from certbot.plugins.dns_test_common import DOMAIN
+from certbot.tests import util as test_util
+
+API_ERROR = digitalocean.DataReadError()
+TOKEN = 'a-token'
+
+
+class AuthenticatorTest(test_util.TempDirTestCase, 
dns_test_common.BaseAuthenticatorTest):
+
+    def setUp(self):
+        from certbot_dns_digitalocean._internal.dns_digitalocean import 
Authenticator
+
+        super(AuthenticatorTest, self).setUp()
+
+        path = os.path.join(self.tempdir, 'file.ini')
+        dns_test_common.write({"digitalocean_token": TOKEN}, path)
+
+        self.config = mock.MagicMock(digitalocean_credentials=path,
+                                     digitalocean_propagation_seconds=0)  # 
don't wait during tests
+
+        self.auth = Authenticator(self.config, "digitalocean")
+
+        self.mock_client = mock.MagicMock()
+        # _get_digitalocean_client | pylint: disable=protected-access
+        self.auth._get_digitalocean_client = 
mock.MagicMock(return_value=self.mock_client)
+
+    def test_perform(self):
+        self.auth.perform([self.achall])
+
+        expected = [mock.call.add_txt_record(DOMAIN, 
'_acme-challenge.'+DOMAIN, mock.ANY)]
+        self.assertEqual(expected, self.mock_client.mock_calls)
+
+    def test_cleanup(self):
+        # _attempt_cleanup | pylint: disable=protected-access
+        self.auth._attempt_cleanup = True
+        self.auth.cleanup([self.achall])
+
+        expected = [mock.call.del_txt_record(DOMAIN, 
'_acme-challenge.'+DOMAIN, mock.ANY)]
+        self.assertEqual(expected, self.mock_client.mock_calls)
+
+
+class DigitalOceanClientTest(unittest.TestCase):
+
+    id_num = 1
+    record_prefix = "_acme-challenge"
+    record_name = record_prefix + "." + DOMAIN
+    record_content = "bar"
+
+    def setUp(self):
+        from certbot_dns_digitalocean._internal.dns_digitalocean import 
_DigitalOceanClient
+
+        self.digitalocean_client = _DigitalOceanClient(TOKEN)
+
+        self.manager = mock.MagicMock()
+        self.digitalocean_client.manager = self.manager
+
+    def test_add_txt_record(self):
+        wrong_domain_mock = mock.MagicMock()
+        wrong_domain_mock.name = "other.invalid"
+        wrong_domain_mock.create_new_domain_record.side_effect = 
AssertionError('Wrong Domain')
+
+        domain_mock = mock.MagicMock()
+        domain_mock.name = DOMAIN
+        domain_mock.create_new_domain_record.return_value = {'domain_record': 
{'id': self.id_num}}
+
+        self.manager.get_all_domains.return_value = [wrong_domain_mock, 
domain_mock]
+
+        self.digitalocean_client.add_txt_record(DOMAIN, self.record_name, 
self.record_content)
+
+        domain_mock.create_new_domain_record.assert_called_with(type='TXT',
+                                                                
name=self.record_prefix,
+                                                                
data=self.record_content)
+
+    def test_add_txt_record_fail_to_find_domain(self):
+        self.manager.get_all_domains.return_value = []
+
+        self.assertRaises(errors.PluginError,
+                          self.digitalocean_client.add_txt_record,
+                          DOMAIN, self.record_name, self.record_content)
+
+    def test_add_txt_record_error_finding_domain(self):
+        self.manager.get_all_domains.side_effect = API_ERROR
+
+        self.assertRaises(errors.PluginError,
+                          self.digitalocean_client.add_txt_record,
+                          DOMAIN, self.record_name, self.record_content)
+
+    def test_add_txt_record_error_creating_record(self):
+        domain_mock = mock.MagicMock()
+        domain_mock.name = DOMAIN
+        domain_mock.create_new_domain_record.side_effect = API_ERROR
+
+        self.manager.get_all_domains.return_value = [domain_mock]
+
+        self.assertRaises(errors.PluginError,
+                          self.digitalocean_client.add_txt_record,
+                          DOMAIN, self.record_name, self.record_content)
+
+    def test_del_txt_record(self):
+        first_record_mock = mock.MagicMock()
+        first_record_mock.type = 'TXT'
+        first_record_mock.name = "DIFFERENT"
+        first_record_mock.data = self.record_content
+
+        correct_record_mock = mock.MagicMock()
+        correct_record_mock.type = 'TXT'
+        correct_record_mock.name = self.record_prefix
+        correct_record_mock.data = self.record_content
+
+        last_record_mock = mock.MagicMock()
+        last_record_mock.type = 'TXT'
+        last_record_mock.name = self.record_prefix
+        last_record_mock.data = "DIFFERENT"
+
+        domain_mock = mock.MagicMock()
+        domain_mock.name = DOMAIN
+        domain_mock.get_records.return_value = [first_record_mock,
+                                                correct_record_mock,
+                                                last_record_mock]
+
+        self.manager.get_all_domains.return_value = [domain_mock]
+
+        self.digitalocean_client.del_txt_record(DOMAIN, self.record_name, 
self.record_content)
+
+        self.assertTrue(correct_record_mock.destroy.called)
+
+        self.assertFalse(first_record_mock.destroy.call_args_list)
+        self.assertFalse(last_record_mock.destroy.call_args_list)
+
+    def test_del_txt_record_error_finding_domain(self):
+        self.manager.get_all_domains.side_effect = API_ERROR
+
+        self.digitalocean_client.del_txt_record(DOMAIN, self.record_name, 
self.record_content)
+
+    def test_del_txt_record_error_finding_record(self):
+        domain_mock = mock.MagicMock()
+        domain_mock.name = DOMAIN
+        domain_mock.get_records.side_effect = API_ERROR
+
+        self.manager.get_all_domains.return_value = [domain_mock]
+
+        self.digitalocean_client.del_txt_record(DOMAIN, self.record_name, 
self.record_content)
+
+    def test_del_txt_record_error_deleting_record(self):
+        record_mock = mock.MagicMock()
+        record_mock.type = 'TXT'
+        record_mock.name = self.record_prefix
+        record_mock.data = self.record_content
+        record_mock.destroy.side_effect = API_ERROR
+
+        domain_mock = mock.MagicMock()
+        domain_mock.name = DOMAIN
+        domain_mock.get_records.return_value = [record_mock]
+
+        self.manager.get_all_domains.return_value = [domain_mock]
+
+        self.digitalocean_client.del_txt_record(DOMAIN, self.record_name, 
self.record_content)
+
+
+if __name__ == "__main__":
+    unittest.main()  # pragma: no cover


Reply via email to