From bbd8424995188238f9f60aaf86d9d33ca52034c5 Mon Sep 17 00:00:00 2001
From: Inso <insomniak.fr@gmail.com>
Date: Sun, 6 Sep 2015 17:04:14 +0200
Subject: [PATCH] Certification in empty community

---
 src/cutecoin/core/net/api/bma/access.py       |   2 -
 src/cutecoin/gui/certification.py             |  33 +++-
 src/cutecoin/gui/community_view.py            |   3 +-
 src/cutecoin/tests/certification/__init__.py  |   0
 .../tests/certification/test_certification.py |  97 ++++++++++++
 .../tests/mocks/bma/init_new_community.py     | 146 ++++++++++++++++++
 .../tests/mocks/bma/new_blockchain.py         |   4 +-
 7 files changed, 275 insertions(+), 10 deletions(-)
 create mode 100644 src/cutecoin/tests/certification/__init__.py
 create mode 100644 src/cutecoin/tests/certification/test_certification.py
 create mode 100644 src/cutecoin/tests/mocks/bma/init_new_community.py

diff --git a/src/cutecoin/core/net/api/bma/access.py b/src/cutecoin/core/net/api/bma/access.py
index a813a2d5..c6e766a0 100644
--- a/src/cutecoin/core/net/api/bma/access.py
+++ b/src/cutecoin/core/net/api/bma/access.py
@@ -157,8 +157,6 @@ class BmaAccess(QObject):
         cache_key = BmaAccess._gen_cache_key(request, req_args, get_args)
 
         if need_reload:
-            # Move to network nstead of community
-            # after removing qthreads
             if cache_key in self._pending_requests:
                 if caller not in self._pending_requests[cache_key]:
                     logging.debug("New caller".format(caller))
diff --git a/src/cutecoin/gui/certification.py b/src/cutecoin/gui/certification.py
index ca55ef33..23201927 100644
--- a/src/cutecoin/gui/certification.py
+++ b/src/cutecoin/gui/certification.py
@@ -5,10 +5,11 @@ Created on 24 dec. 2014
 """
 from PyQt5.QtWidgets import QDialog, QMessageBox, QDialogButtonBox, QApplication
 from PyQt5.QtCore import Qt, pyqtSlot
-import quamash
 from ..gen_resources.certification_uic import Ui_CertificationDialog
 from . import toast
+from ..core.net.api import bma as qtbma
 import asyncio
+import logging
 
 
 class CertificationDialog(QDialog, Ui_CertificationDialog):
@@ -63,17 +64,33 @@ class CertificationDialog(QDialog, Ui_CertificationDialog):
     def handle_error(self, error_code, text):
         if self.app.preferences['notifications']:
             toast.display(self.tr("Error"), self.tr("{0} : {1}".format(error_code, text)))
-        else:
-            QMessageBox.Critical(self, self.tr("Error", self.tr("{0} : {1}".format(error_code, text))))
+        #else:
+        #    QMessageBox.Critical(self, self.tr("Error", self.tr("{0} : {1}".format(error_code, text))))
         self.account.certification_broadcasted.disconnect()
         self.account.broadcast_error.disconnect(self.handle_error)
         QApplication.restoreOverrideCursor()
 
+    def handle_community_data_change(self, request):
+        if request == qtbma.blockchain.Block:
+            self.refresh()
+
     def change_current_community(self, index):
+        try:
+            self.community.inner_data_changed.disconnect(self.handle_community_data_change)
+        except TypeError as e:
+            if 'connect' in str(e):
+                logging.debug("Error when disconnecting community")
+            else:
+                raise
         self.community = self.account.communities[index]
-        if self.account.pubkey in self.community.members_pubkeys():
+        self.community.inner_data_changed.connect(self.handle_community_data_change)
+        self.refresh()
+
+    def refresh(self):
+        if self.account.pubkey in self.community.members_pubkeys() \
+                or self.community.get_block(0) == qtbma.blockchain.Block.null_value:
             self.button_box.button(QDialogButtonBox.Ok).setEnabled(True)
-            self.button_box.button(QDialogButtonBox.Ok).setText(self.tr("Ok"))
+            self.button_box.button(QDialogButtonBox.Ok).setText(self.tr("&Ok"))
         else:
             self.button_box.button(QDialogButtonBox.Ok).setEnabled(False)
             self.button_box.button(QDialogButtonBox.Ok).setText(self.tr("Not a member"))
@@ -81,3 +98,9 @@ class CertificationDialog(QDialog, Ui_CertificationDialog):
     def recipient_mode_changed(self, pubkey_toggled):
         self.edit_pubkey.setEnabled(pubkey_toggled)
         self.combo_contact.setEnabled(not pubkey_toggled)
+
+    def async_exec(self):
+        future = asyncio.Future()
+        self.finished.connect(lambda r: future.set_result(r))
+        self.open()
+        return future
\ No newline at end of file
diff --git a/src/cutecoin/gui/community_view.py b/src/cutecoin/gui/community_view.py
index de3563c1..127c8326 100644
--- a/src/cutecoin/gui/community_view.py
+++ b/src/cutecoin/gui/community_view.py
@@ -195,7 +195,8 @@ class CommunityWidget(QWidget, Ui_CommunityWidget):
                         logging.debug("Not a member")
                         self.button_membership.setText(self.tr("Send membership demand"))
                         self.button_membership.show()
-                        self.button_certification.hide()
+                        if self.community.get_block(0) != qtbma.blockchain.Block.null_value:
+                            self.button_certification.hide()
                 else:
                     logging.debug("UID not published")
                     self.button_membership.hide()
diff --git a/src/cutecoin/tests/certification/__init__.py b/src/cutecoin/tests/certification/__init__.py
new file mode 100644
index 00000000..e69de29b
diff --git a/src/cutecoin/tests/certification/test_certification.py b/src/cutecoin/tests/certification/test_certification.py
new file mode 100644
index 00000000..0dd7d189
--- /dev/null
+++ b/src/cutecoin/tests/certification/test_certification.py
@@ -0,0 +1,97 @@
+import sys
+import unittest
+import asyncio
+import quamash
+import time
+import logging
+from ucoinpy.documents.peer import BMAEndpoint as PyBMAEndpoint
+from PyQt5.QtWidgets import QDialog, QDialogButtonBox
+from PyQt5.QtCore import QLocale, Qt
+from PyQt5.QtTest import QTest
+from cutecoin.tests.mocks.bma import init_new_community
+from cutecoin.tests.mocks.access_manager import MockNetworkAccessManager
+from cutecoin.core.registry.identities import IdentitiesRegistry
+from cutecoin.gui.certification import CertificationDialog
+from cutecoin.gui.password_asker import PasswordAskerDialog
+from cutecoin.core.app import Application
+from cutecoin.core import Account, Community, Wallet
+from cutecoin.core.net import Network, Node
+from cutecoin.core.net.endpoint import BMAEndpoint
+from cutecoin.core.net.api.bma.access import BmaAccess
+from cutecoin.tests import get_application
+from cutecoin.core.net.api import bma as qtbma
+
+
+class TestCertificationDialog(unittest.TestCase):
+    def setUp(self):
+        self.qapplication = get_application()
+        self.network_manager = MockNetworkAccessManager()
+        QLocale.setDefault(QLocale("en_GB"))
+        self.lp = quamash.QEventLoop(self.qapplication)
+        asyncio.set_event_loop(self.lp)
+        self.identities_registry = IdentitiesRegistry()
+
+        self.application = Application(self.qapplication, self.lp, self.network_manager, self.identities_registry)
+        self.application.preferences['notifications'] = False
+
+        self.endpoint = BMAEndpoint(PyBMAEndpoint("", "127.0.0.1", "", 50000))
+        self.node = Node(self.network_manager, "test_currency", [self.endpoint],
+                         "", "HnFcSms8jzwngtVomTTnzudZx7SHUQY8sVE1y8yBmULk",
+                         qtbma.blockchain.Block.null_value, Node.ONLINE,
+                         time.time(), {}, "ucoin", "0.14.0", 0)
+        self.network = Network.create(self.network_manager, self.node)
+        self.bma_access = BmaAccess.create(self.network)
+        self.community = Community("test_currency", self.network, self.bma_access)
+
+        self.wallet = Wallet(0, "7Aqw6Efa9EzE7gtsc8SveLLrM7gm6NEGoywSv4FJx6pZ",
+                             "Wallet 1", self.identities_registry)
+
+        # Salt/password : "testcutecoin/testcutecoin"
+        # Pubkey : 7Aqw6Efa9EzE7gtsc8SveLLrM7gm6NEGoywSv4FJx6pZ
+        self.account = Account("testcutecoin", "7Aqw6Efa9EzE7gtsc8SveLLrM7gm6NEGoywSv4FJx6pZ",
+                               "john", [self.community], [self.wallet], [], self.identities_registry)
+
+        self.password_asker = PasswordAskerDialog(self.account)
+        self.password_asker.password = "testcutecoin"
+        self.password_asker.remember = True
+
+    def tearDown(self):
+        try:
+            self.lp.close()
+        finally:
+            asyncio.set_event_loop(None)
+
+    def test_certification_init_community(self):
+        certification_dialog = CertificationDialog(self.application,
+                                                   self.account,
+                                                   self.password_asker)
+
+        @asyncio.coroutine
+        def open_dialog(certification_dialog):
+            result = yield from certification_dialog.async_exec()
+            self.assertEqual(result, QDialog.Accepted)
+
+        def close_dialog():
+            if certification_dialog.isVisible():
+                certification_dialog.close()
+
+        @asyncio.coroutine
+        def exec_test():
+            mock = init_new_community.get_mock()
+            logging.debug(mock.pretend_url)
+            yield from asyncio.sleep(1)
+            self.network_manager.set_mock_path(mock.pretend_url)
+            self.assertEqual(certification_dialog.button_box.button(QDialogButtonBox.Ok).text(), "&Ok")
+            QTest.mouseClick(certification_dialog.radio_pubkey, Qt.LeftButton)
+            QTest.keyClicks(certification_dialog.edit_pubkey, "FADxcH5LmXGmGFgdixSes6nWnC4Vb4pRUBYT81zQRhjn")
+            QTest.mouseClick(certification_dialog.button_box.button(QDialogButtonBox.Ok), Qt.LeftButton)
+
+        self.lp.call_later(15, close_dialog)
+        asyncio.async(exec_test())
+        self.lp.run_until_complete(open_dialog(certification_dialog))
+
+
+if __name__ == '__main__':
+    logging.basicConfig(stream=sys.stderr)
+    logging.getLogger().setLevel(logging.DEBUG)
+    unittest.main()
diff --git a/src/cutecoin/tests/mocks/bma/init_new_community.py b/src/cutecoin/tests/mocks/bma/init_new_community.py
new file mode 100644
index 00000000..cb4700e3
--- /dev/null
+++ b/src/cutecoin/tests/mocks/bma/init_new_community.py
@@ -0,0 +1,146 @@
+from pretenders.client.http import HTTPMock
+from pretenders.common.constants import FOREVER
+
+bma_peering = b"""{
+  "version": 1,
+  "currency": "test_currency",
+  "endpoints": [
+    "BASIC_MERKLED_API localhost 127.0.0.1 50000"
+  ],
+  "status": "UP",
+  "block": "30152-00003E7F9234E7542FCF669B69B0F84FF79CCCD3",
+  "signature": "cXuqZuDfyHvxYAEUkPH1TQ1M+8YNDpj8kiHGYi3LIaMqEdVqwVc4yQYGivjxFMYyngRfxXkyvqBKZA6rKOulCA==",
+  "raw": "Version: 1\\nType: Peer\\nCurrency: meta_brouzouf\\nPublicKey: HnFcSms8jzwngtVomTTnzudZx7SHUQY8sVE1y8yBmULk\\nBlock: 30152-00003E7F9234E7542FCF669B69B0F84FF79CCCD3\\nEndpoints:\\nBASIC_MERKLED_API localhost 127.0.0.1 50000\\n",
+  "pubkey": "HnFcSms8jzwngtVomTTnzudZx7SHUQY8sVE1y8yBmULk"
+}"""
+
+bma_lookup_test_john = b"""{
+  "partial": false,
+  "results": [
+    {
+      "pubkey": "7Aqw6Efa9EzE7gtsc8SveLLrM7gm6NEGoywSv4FJx6pZ",
+      "uids": [
+        {
+          "uid": "john",
+          "meta": {
+            "timestamp": 1441130831
+          },
+          "self": "ZrHK0cCqrxWReROK0ciiSb45+dRphJa68qFaSjdve8bBdnGAu7+DIu0d+u/fXrNRXuObihOKMBIawaIVPNHqDw==",
+          "others": []
+        }
+      ],
+      "signed": []
+    }
+  ]
+}"""
+
+bma_lookup_test_doe = b"""{
+  "partial": false,
+  "results": [
+    {
+      "pubkey": "FADxcH5LmXGmGFgdixSes6nWnC4Vb4pRUBYT81zQRhjn",
+      "uids": [
+        {
+          "uid": "doe",
+          "meta": {
+            "timestamp": 1441130831
+          },
+          "self": "cIkHPQQ5+xTb4cKWv85rcYcZT+E3GDtX8B2nCK9Vs12p2Yz4bVaZiMvBBwisAAy2WBOaqHS3ydpXGtADchOICw==",
+          "others": []
+        }
+      ],
+      "signed": []
+    }
+  ]
+}"""
+
+bma_lookup_test_patrick = b"""{
+  "partial": false,
+  "results": [
+    {
+      "pubkey": "FADxcH5LmXGmGFgdixSes6nWnC4Vb4pRUBYT81zQRhjn",
+      "uids": [
+        {
+          "uid": "patrick",
+          "meta": {
+            "timestamp": 1441130831
+          },
+          "self": "QNX2HDAxcHawc47TnMqb5/ou2lwa+zYOyeNk0a52dQDJX/NWmeTzGfTjdCtjpXmSCuPSg0F1mOnLQVd60xAzDA==",
+          "others": []
+        }
+      ],
+      "signed": []
+    }
+  ]
+}"""
+
+
+def get_mock():
+    mock = HTTPMock('127.0.0.1', 50000)
+
+    mock.when('GET /network/peering')\
+        .reply(body=bma_peering,
+                times=FOREVER,
+                headers={'Content-Type': 'application/json'})
+
+    mock.when('GET /blockchain/block/0')\
+        .reply(body=b"Block not found",
+               status=404,
+               times=FOREVER,
+                headers={'Content-Type': 'application/json'})
+
+    mock.when('GET /blockchain/current')\
+        .reply(body=b"Block not found",
+               status=404,
+               times=FOREVER,
+                headers={'Content-Type': 'application/json'})
+
+    mock.when('GET /wot/certifiers-of/7Aqw6Efa9EzE7gtsc8SveLLrM7gm6NEGoywSv4FJx6pZ')\
+            .reply(body=b"No member matching this pubkey or uid",
+                status=404,
+                times=1,
+                headers={'Content-Type': 'application/json'})
+
+    mock.when('GET /wot/lookup/john')\
+            .reply(body=bma_lookup_test_john,
+                status=200,
+                times=1,
+                headers={'Content-Type': 'application/json'})
+
+    mock.when('GET /wot/lookup/7Aqw6Efa9EzE7gtsc8SveLLrM7gm6NEGoywSv4FJx6pZ')\
+            .reply(body=bma_lookup_test_john,
+                status=200,
+                times=1,
+                headers={'Content-Type': 'application/json'})
+
+    mock.when('GET /wot/lookup/doe')\
+            .reply(body=bma_lookup_test_doe,
+                status=200,
+                times=1,
+                headers={'Content-Type': 'application/json'})
+
+    mock.when('GET /wot/lookup/FADxcH5LmXGmGFgdixSes6nWnC4Vb4pRUBYT81zQRhjn')\
+            .reply(body=bma_lookup_test_doe,
+                status=200,
+                times=1,
+                headers={'Content-Type': 'application/json'})
+
+    mock.when('GET /wot/lookup/patrick')\
+            .reply(body=bma_lookup_test_patrick,
+                status=200,
+                times=1,
+                headers={'Content-Type': 'application/json'})
+
+    mock.when('GET /wot/lookup/FADxcH5LmXGmGFgdixSes6nWnC4Vb4pRUBYT81zQRhjn')\
+            .reply(body=bma_lookup_test_patrick,
+                status=200,
+                times=1,
+                headers={'Content-Type': 'application/json'})
+
+    mock.when('POST /wot/add.*')\
+        .reply(body=b"{}",
+               status=200,
+               times=FOREVER,
+               headers={'Content-Type': 'application/json'})
+
+    return mock
diff --git a/src/cutecoin/tests/mocks/bma/new_blockchain.py b/src/cutecoin/tests/mocks/bma/new_blockchain.py
index 71f2932b..fe43d5d2 100644
--- a/src/cutecoin/tests/mocks/bma/new_blockchain.py
+++ b/src/cutecoin/tests/mocks/bma/new_blockchain.py
@@ -3,7 +3,7 @@ from pretenders.common.constants import FOREVER
 
 bma_peering = b"""{
   "version": 1,
-  "currency": "meta_brouzouf",
+  "currency": "test_currency",
   "endpoints": [
     "BASIC_MERKLED_API localhost 127.0.0.1 50000"
   ],
@@ -37,7 +37,7 @@ def get_mock():
                 times=FOREVER,
                 headers={'Content-Type': 'application/json'})
 
-    mock.when('GET /blockchain/Block/0')\
+    mock.when('GET /blockchain/block/0')\
         .reply(body=b"Block not found",
                status=404,
                times=FOREVER,
-- 
GitLab