class UserScenario(metaclass=ABCMeta):
    def __init__(self, seed, logFileName=None):
        if logFileName:
            Logger().enableFileLogging(logFileName)

        self._seed = seed

        self._client = None
        self._wallet = None

        self._looper = None

    @property
    def identifier(self):
        if self._wallet:
            return self._wallet.defaultId
        else:
            return None

    @property
    def verkey(self):
        if self._wallet:
            return self._wallet.getVerkey()
        else:
            return None

    @classmethod
    def runInstance(cls, *args, **kwargs):
        cls(*args, **kwargs).run()

    def run(self):
        try:
            self._createClientAndWallet()

            self._looper = Looper(debug=getConfig().LOOPER_DEBUG)
            try:
                self._startClient()
                self.do()
            finally:
                self._looper.shutdownSync()
                self._looper = None

        except BaseException as ex:
            logger.exception(
                "User scenario throws out exception: {}".format(ex),
                exc_info=ex)
            raise ex

    @abstractmethod
    def do(self):
        pass

    def performOperation(self, op):
        req = self._wallet.signOp(op)
        self._client.submitReqs(req)

        def getRequestResult(reqKey):
            reply, error = self._client.replyIfConsensus(*reqKey)
            if reply is None and error is None:
                raise Exception("Request has not been completed yet")
            else:
                return reply, error

        reply, error = self._looper.run(
            eventually(partial(getRequestResult, req.key),
                       retryWait=.5,
                       timeout=5))
        assert not error, error

        if reply[DATA]:
            result = json.loads(reply[DATA])
        else:
            result = None

        return result

    def generateNewSigner(self):
        assert self.identifier
        return SimpleSigner(identifier=self.identifier)

    def changeSigner(self, newSigner):
        assert newSigner.identifier == self.identifier
        self._wallet.updateSigner(self.identifier, newSigner)
        logger.info("Changed signer. New verkey: {}".format(self.verkey))

    def _createClientAndWallet(self):
        signer = SimpleSigner(seed=self._seed)

        port = genHa()[1]
        ha = HA('0.0.0.0', port)
        self._client = Client(name=signer.identifier, ha=ha)

        self._wallet = Wallet(name=signer.identifier)
        self._wallet.addIdentifier(signer=signer)

        logger.info("Identifier: {}".format(self.identifier))
        logger.info("Signer's verkey: {}".format(self.verkey))

    def _startClient(self):
        self._looper.add(self._client)

        def ensureConnectedToAll():
            connectedNodes = self._client.nodestack.connecteds
            connectedNodesNum = len(connectedNodes)
            totalNodes = len(self._client.nodeReg)

            logger.info("Connected {} / {} nodes".format(
                connectedNodesNum, totalNodes))
            for node in connectedNodes:
                logger.info("  {}".format(node))

            if connectedNodesNum == 0:
                raise Exception("Not connected to any")
            elif connectedNodesNum < totalNodes * 0.8:
                raise Exception("Not connected fully")
            else:
                return True

        self._looper.run(
            eventually(ensureConnectedToAll, retryWait=.5, timeout=5))
Exemple #2
0
def test_hasProdable():
    looper = Looper(autoStart=False)
    with pytest.raises(ValueError):
        Looper().hasProdable(Prodable(), 'prodable')
    looper.shutdownSync()