Repository: vinteumorg/Floresta
Pull request #434: Fix non stop florestad process in functional tests
Author: login: qlrd
Created: 2025-03-31T13:07:56Z | Merged: 2025-04-11T15:54:32Z

Fix #426 

### What is the purpose of this pull request?

- [x] Bug fix
- [ ] Documentation update
- [ ] New feature
- [x] Test
- [ ] Other: <!-- Please describe it -->

### Which crates are being modified?

- [ ] floresta-chain
- [ ] floresta-cli
- [ ] floresta-common
- [ ] floresta-compact-filters
- [ ] floresta-electrum
- [ ] floresta-watch-only
- [ ] floresta-wire
- [ ] floresta
- [ ] florestad
- [x] Other: functional tests

### Description

Added a pipeline for assertions, where a failure of a condition start a node's shutdown procedure. The pipeline can be used with these methods:

* assertTrue for boolean condition;

* assertEqual for expected general condition;

* assertIn for expected item in a list;

* assertMatch for expected strings in a given regex pattern;

* assertRaises for expected exceptions.

The pipeline was applied in these suites:

* Added assertion pipeline to example suite;

* Added assertion pipeline to floresta-cli suite;

* Added assertion pipeline to florestad suite.

### Notes to the reviewers

This PR depends on #431 to work without false positives.

<!-- In this section you can include notes directed to the reviewers, like explaining why some parts of the PR were done in a specific way -->

### Checklist

- [x] I've signed all my commits
- [x] I ran `just lint`
- [x] I ran `cargo test`
- [x] I've checked the integration tests
- [x] I've followed the [contribution guidelines](https://github.com/vinteumorg/Floresta/blob/master/CONTRIBUTING.md)
- [x] I'm linking the issue being fixed by this PR (if any)


Linked issue #426: [Bug] Florestad do not stop when functional test fail
**Describe the bug**  

When a test break (generally by assertion failure), a developer will not be able to run the test again while not kill the process and close the opened ports that `florestad` started.

```python
def run_test(self):
    assert False 
    
    # This won't be called
    self.stop_node(TestSslInitialization.nodes[0])
```

**Steps to Reproduce**  

Edit the `example/example-test.py` test and insert this at the end of `run_test` function:

```diff
 class ExampleTest(FlorestaTestFramework):
@@ -106,6 +107,7 @@ class ExampleTest(FlorestaTestFramework):
         assert inf_response["best_block"] == ExampleTest.expected_block
         assert inf_response["difficulty"] == ExampleTest.expected_difficulty
         assert inf_response["leaf_count"] == ExampleTest.expected_leaf_count
+        assert False
```

Run the test:

```bash
uv run tests/run_tests.py
```

Wait for it break; you will receive an `AssertionError` like this:

```bash
Traceback (most recent call last):
  File "/home/user/github/Floresta/tests/example/example-test.py", line 114, in <module>
    ExampleTest().main()
  File "/home/user/Floresta/tests/test_framework/test_framework.py", line 110, in main
    self.run_test()
  File "/home/user/Floresta/tests/example/example-test.py", line 110, in run_test
    assert False
           ^^^^^
AssertionError
```

Now run remove the change:

```diff
 class ExampleTest(FlorestaTestFramework):
@@ -106,6 +107,7 @@ class ExampleTest(FlorestaTestFramework):
         assert inf_response["best_block"] == ExampleTest.expected_block
         assert inf_response["difficulty"] == ExampleTest.expected_difficulty
         assert inf_response["leaf_count"] == ExampleTest.expected_leaf_count
-        assert False
```

And run the tests again. 

**Expected behavior**  

The error will change to something like:

```bash
  File "/home/user/github/Floresta/tests/test_framework/electrum_client.py", line 22, in __init__
    s.connect((host, port))
OSError: [Errno 49] Can't assign requested address
```
                
**Build environment**

version 0.7.0-75-g0f1d569-dirty compiled for aarch64-macos- with rustc 1.87.0-nightly (b48576b4d 2025-03-22)
          
**Additional context** 

No additional context.


Linked issue comments: user: login: qlrd
created_at: 2025-03-26T11:59:46Z
body: In a talk with @Davidson-Souza, it has been hypothesized that run_test.py is a child process of bash (or uv) and that it executes a sequence of other child processes (bash/uv being a grandparent process). In turn, the "grandchild" process executes another "great-grandchild" process (`florestad --network regtest`).

When the `assert` expression fails, the "grandchild" process is terminated, but the "great-grandchild" process is not. This in turn becomes the property of the grandparent process, keeping the process and, in turn, port 18443 open, making new tests impossible.

It would therefore be interesting to avoid native expressions such as `assert <condition>` and replace them with methods similar to pylint, where if a condition fails, a cleanup procedure could be called. For example:


```bash
class FlorestaTestFramework(metaclass=FlorestaTestMetaClass)
...

    def assertEqual(condition: Any, expected: Any, message: str = "Assertion failed"):
        if not condition == expected:
            self.log(message)
            self.stop()
        else:
            pass
```
author_association: CONTRIBUTOR
user: login: luisschwab
created_at: 2025-03-26T16:40:40Z
body: You could also do a `try...catch` to shut the node down in case of an error.
author_association: MEMBER
user: login: qlrd
created_at: 2025-03-27T13:08:20Z
body: > You could also do a `try...catch` to shut the node down in case of an error.

Good! Even `if` clause pass, the `try catch` can get some other errors. I'll put that too
author_association: CONTRIBUTOR
user: login: qlrd
created_at: 2025-03-28T18:27:28Z
body: Waiting for #431 to push the PR
author_association: CONTRIBUTOR
user: login: qlrd
created_at: 2025-03-31T13:01:14Z
body: > You could also do a `try...catch` to shut the node down in case of an error.

@luisschwab, made an `assertRaises` method to it.
author_association: CONTRIBUTOR

Diff:
diff --git a/tests/example/example-test.py b/tests/example/example-test.py
index d41c5a800..88383e47d 100644
--- a/tests/example/example-test.py
+++ b/tests/example/example-test.py
@@ -44,9 +44,9 @@
 """
 
 import json
-from test_framework.test_framework import FlorestaTestFramework
 from test_framework.electrum_client import ElectrumClient
 from test_framework.floresta_rpc import REGTEST_RPC_SERVER
+from test_framework.test_framework import FlorestaTestFramework
 
 
 class ExampleTest(FlorestaTestFramework):
@@ -99,13 +99,20 @@ def run_test(self):
         electrum = ElectrumClient("localhost", 50001)
         rpc_response = json.loads(electrum.get_version())
 
-        # Make assertions
-        assert rpc_response["result"][0] == ExampleTest.expected_version[0]
-        assert rpc_response["result"][1] == ExampleTest.expected_version[1]
-        assert inf_response["height"] == ExampleTest.expected_height
-        assert inf_response["best_block"] == ExampleTest.expected_block
-        assert inf_response["difficulty"] == ExampleTest.expected_difficulty
-        assert inf_response["leaf_count"] == ExampleTest.expected_leaf_count
+        # Make assertions with our framework. Avoid usage of
+        # native `assert` clauses. For more information, see
+        # https://github.com/vinteumorg/Floresta/issues/426
+        self.assertEqual(rpc_response["result"][0], ExampleTest.expected_version[0])
+        self.assertEqual(rpc_response["result"][1], ExampleTest.expected_version[1])
+        self.assertEqual(inf_response["height"], ExampleTest.expected_height)
+        self.assertEqual(inf_response["best_block"], ExampleTest.expected_block)
+        self.assertEqual(inf_response["difficulty"], ExampleTest.expected_difficulty)
+        self.assertEqual(inf_response["leaf_count"], ExampleTest.expected_leaf_count)
+
+        # At the end, you should stop all nodes with the `stop`
+        # method. Alternatively, you can use `stop_node(int) where int`
+        # is the node index
+        self.stop()
 
 
 if __name__ == "__main__":
diff --git a/tests/floresta-cli/addnode-test.py b/tests/floresta-cli/addnode-test.py
index 8b2bc19b9..ca64f3566 100644
--- a/tests/floresta-cli/addnode-test.py
+++ b/tests/floresta-cli/addnode-test.py
@@ -6,8 +6,9 @@
 
 import os
 import tempfile
-from test_framework.test_framework import FlorestaTestFramework
+
 from test_framework.floresta_rpc import REGTEST_RPC_SERVER, JSONRPCError
+from test_framework.test_framework import FlorestaTestFramework
 
 # Setup a little node with another port
 ANOTHER_REGTEST_RPC_SERVER = {
@@ -87,18 +88,13 @@ def run_test(self):
         self.wait_for_rpc_connection(GetAddnodeIDBErrorTest.nodes[1])
 
         # Test assertions
-        try:
-            node = self.get_node(GetAddnodeIDBErrorTest.nodes[0])
-            success = node.get_addnode(node="0.0.0.0:18443")
-            assert success
-        except JSONRPCError as exc:
-            assert exc.code == -32603
-            assert exc.message == GetAddnodeIDBErrorTest.node_ibd_error
-            assert exc.data is None
-        finally:
-            # stop nodes
-            self.stop_node(GetAddnodeIDBErrorTest.nodes[1])
-            self.stop_node(GetAddnodeIDBErrorTest.nodes[0])
+        node = self.get_node(GetAddnodeIDBErrorTest.nodes[0])
+        result = node.get_addnode(node="0.0.0.0:18443")
+        self.assertTrue(result)
+
+        # stop nodes
+        self.stop_node(GetAddnodeIDBErrorTest.nodes[1])
+        self.stop_node(GetAddnodeIDBErrorTest.nodes[0])
 
 
 if __name__ == "__main__":
diff --git a/tests/floresta-cli/getblock-test.py b/tests/floresta-cli/getblock-test.py
index 62f051fe4..b50c0e5db 100644
--- a/tests/floresta-cli/getblock-test.py
+++ b/tests/floresta-cli/getblock-test.py
@@ -4,8 +4,8 @@
 This functional test cli utility to interact with a Floresta node with `getblock`
 """
 
-from test_framework.test_framework import FlorestaTestFramework
 from test_framework.floresta_rpc import REGTEST_RPC_SERVER
+from test_framework.test_framework import FlorestaTestFramework
 
 
 class GetBlockTest(FlorestaTestFramework):
@@ -62,24 +62,24 @@ def run_test(self):
 
         # Test verbose level 1
         response = node.get_block(GetBlockTest.block, 1)
-        assert response["bits"] == GetBlockTest.bits
-        assert response["chainwork"] == GetBlockTest.chainwork
-        assert response["confirmations"] == GetBlockTest.confirmations
-        assert response["difficulty"] == GetBlockTest.difficulty
-        assert response["hash"] == GetBlockTest.hash
-        assert response["height"] == GetBlockTest.height
-        assert response["mediantime"] == GetBlockTest.mediantime
-        assert response["merkleroot"] == GetBlockTest.merkleroot
-        assert response["n_tx"] == GetBlockTest.n_tx
-        assert response["nonce"] == GetBlockTest.nonce
-        assert response["previousblockhash"] == GetBlockTest.prev_blockhash
-        assert response["size"] == GetBlockTest.size
-        assert response["strippedsize"] == GetBlockTest.strippedsize
-        assert response["time"] == GetBlockTest.time
-        assert len(response["tx"]) == len(GetBlockTest.tx)
-        assert response["version"] == GetBlockTest.version
-        assert response["versionHex"] == GetBlockTest.version_hex
-        assert response["weight"] == GetBlockTest.weight
+        self.assertEqual(response["bits"], GetBlockTest.bits)
+        self.assertEqual(response["chainwork"], GetBlockTest.chainwork)
+        self.assertEqual(response["confirmations"], GetBlockTest.confirmations)
+        self.assertEqual(response["difficulty"], GetBlockTest.difficulty)
+        self.assertEqual(response["hash"], GetBlockTest.hash)
+        self.assertEqual(response["height"], GetBlockTest.height)
+        self.assertEqual(response["mediantime"], GetBlockTest.mediantime)
+        self.assertEqual(response["merkleroot"], GetBlockTest.merkleroot)
+        self.assertEqual(response["n_tx"], GetBlockTest.n_tx)
+        self.assertEqual(response["nonce"], GetBlockTest.nonce)
+        self.assertEqual(response["previousblockhash"], GetBlockTest.prev_blockhash)
+        self.assertEqual(response["size"], GetBlockTest.size)
+        self.assertEqual(response["strippedsize"], GetBlockTest.strippedsize)
+        self.assertEqual(response["time"], GetBlockTest.time)
+        self.assertEqual(len(response["tx"]), len(GetBlockTest.tx))
+        self.assertEqual(response["version"], GetBlockTest.version)
+        self.assertEqual(response["versionHex"], GetBlockTest.version_hex)
+        self.assertEqual(response["weight"], GetBlockTest.weight)
 
         # Shutdown node
         self.stop_node(GetBlockTest.nodes[0])
diff --git a/tests/floresta-cli/getblockchaininfo-test.py b/tests/floresta-cli/getblockchaininfo-test.py
index fd99001f9..94b841cbb 100644
--- a/tests/floresta-cli/getblockchaininfo-test.py
+++ b/tests/floresta-cli/getblockchaininfo-test.py
@@ -4,8 +4,8 @@
 This functional test cli utility to interact with a Floresta node with `getblockchaininfo`
 """
 
-from test_framework.test_framework import FlorestaTestFramework
 from test_framework.floresta_rpc import REGTEST_RPC_SERVER
+from test_framework.test_framework import FlorestaTestFramework
 
 
 class GetBlockchaininfoTest(FlorestaTestFramework):
@@ -45,17 +45,19 @@ def run_test(self):
         # Test assertions
         node = self.get_node(GetBlockchaininfoTest.nodes[0])
         response = node.get_blockchain_info()
-        assert response["best_block"] == GetBlockchaininfoTest.best_block
-        assert response["difficulty"] == GetBlockchaininfoTest.difficulty
-        assert response["height"] == GetBlockchaininfoTest.height
-        assert response["ibd"] == GetBlockchaininfoTest.ibd
-        assert response["latest_block_time"] == GetBlockchaininfoTest.latest_block_time
-        assert response["latest_work"] == GetBlockchaininfoTest.latest_work
-        assert response["leaf_count"] == GetBlockchaininfoTest.leaf_count
-        assert response["progress"] == GetBlockchaininfoTest.progress
-        assert response["root_count"] == GetBlockchaininfoTest.root_count
-        assert response["root_hashes"] == GetBlockchaininfoTest.root_hashes
-        assert response["validated"] == GetBlockchaininfoTest.validated
+        self.assertEqual(response["best_block"], GetBlockchaininfoTest.best_block)
+        self.assertEqual(response["difficulty"], GetBlockchaininfoTest.difficulty)
+        self.assertEqual(response["height"], GetBlockchaininfoTest.height)
+        self.assertEqual(response["ibd"], GetBlockchaininfoTest.ibd)
+        self.assertEqual(
+            response["latest_block_time"], GetBlockchaininfoTest.latest_block_time
+        )
+        self.assertEqual(response["latest_work"], GetBlockchaininfoTest.latest_work)
+        self.assertEqual(response["leaf_count"], GetBlockchaininfoTest.leaf_count)
+        self.assertEqual(response["progress"], GetBlockchaininfoTest.progress)
+        self.assertEqual(response["root_count"], GetBlockchaininfoTest.root_count)
+        self.assertEqual(response["root_hashes"], GetBlockchaininfoTest.root_hashes)
+        self.assertEqual(response["validated"], GetBlockchaininfoTest.validated)
 
         # Shutdown node
         self.stop_node(GetBlockchaininfoTest.nodes[0])
diff --git a/tests/floresta-cli/getblockhash-test.py b/tests/floresta-cli/getblockhash-test.py
index 0f424f6c9..9bb6d631a 100644
--- a/tests/floresta-cli/getblockhash-test.py
+++ b/tests/floresta-cli/getblockhash-test.py
@@ -4,8 +4,8 @@
 This functional test cli utility to interact with a Floresta node with `getblockhash`
 """
 
-from test_framework.test_framework import FlorestaTestFramework
 from test_framework.floresta_rpc import REGTEST_RPC_SERVER
+from test_framework.test_framework import FlorestaTestFramework
 
 
 class GetBlockhashTest(FlorestaTestFramework):
@@ -35,7 +35,7 @@ def run_test(self):
         # Test assertions
         node = self.get_node(GetBlockhashTest.nodes[0])
         response = node.get_blockhash(0)
-        assert response == GetBlockhashTest.best_block
+        self.assertEqual(response, GetBlockhashTest.best_block)
 
         # Shutdown node
         self.stop_node(GetBlockhashTest.nodes[0])
diff --git a/tests/floresta-cli/getblockheader-test.py b/tests/floresta-cli/getblockheader-test.py
index c503b4eed..96f56fe2d 100644
--- a/tests/floresta-cli/getblockheader-test.py
+++ b/tests/floresta-cli/getblockheader-test.py
@@ -4,8 +4,8 @@
 This functional test cli utility to interact with a Floresta node with `getblockheader`
 """
 
-from test_framework.test_framework import FlorestaTestFramework
 from test_framework.floresta_rpc import REGTEST_RPC_SERVER
+from test_framework.test_framework import FlorestaTestFramework
 
 
 class GetBlockheaderHeightZeroTest(FlorestaTestFramework):
@@ -54,12 +54,16 @@ def run_test(self):
         # Test assertions
         node = self.get_node(GetBlockheaderHeightZeroTest.nodes[0])
         response = node.get_blockheader(GetBlockheaderHeightZeroTest.blockhash)
-        assert response["version"] == GetBlockheaderHeightZeroTest.version
-        assert response["prev_blockhash"] == GetBlockheaderHeightZeroTest.prev_blockhash
-        assert response["merkle_root"] == GetBlockheaderHeightZeroTest.merkle_root
-        assert response["time"] == GetBlockheaderHeightZeroTest.time
-        assert response["bits"] == GetBlockheaderHeightZeroTest.bits
-        assert response["nonce"] == GetBlockheaderHeightZeroTest.nonce
+        self.assertEqual(response["version"], GetBlockheaderHeightZeroTest.version)
+        self.assertEqual(
+            response["prev_blockhash"], GetBlockheaderHeightZeroTest.prev_blockhash
+        )
+        self.assertEqual(
+            response["merkle_root"], GetBlockheaderHeightZeroTest.merkle_root
+        )
+        self.assertEqual(response["time"], GetBlockheaderHeightZeroTest.time)
+        self.assertEqual(response["bits"], GetBlockheaderHeightZeroTest.bits)
+        self.assertEqual(response["nonce"], GetBlockheaderHeightZeroTest.nonce)
 
         # Shutdown node
         self.stop_node(GetBlockheaderHeightZeroTest.nodes[0])
diff --git a/tests/floresta-cli/getmemoryinfo-test.py b/tests/floresta-cli/getmemoryinfo-test.py
index baab77018..8e30c3278 100644
--- a/tests/floresta-cli/getmemoryinfo-test.py
+++ b/tests/floresta-cli/getmemoryinfo-test.py
@@ -8,8 +8,9 @@
 import re
 import sys
 import tempfile
-from test_framework.test_framework import FlorestaTestFramework
+
 from test_framework.floresta_rpc import REGTEST_RPC_SERVER
+from test_framework.test_framework import FlorestaTestFramework
 
 
 class GetMemoryInfoTest(FlorestaTestFramework):
@@ -50,21 +51,21 @@ def test_mode_stats_ibd(self, node):
         """
         if sys.platform == "linux":
             result = node.get_memoryinfo("stats")
-            assert "locked" in result
-            assert "chunks_free" in result["locked"]
-            assert "chunks_used" in result["locked"]
-            assert "free" in result["locked"]
-            assert "locked" in result["locked"]
-            assert "total" in result["locked"]
-            assert "used" in result["locked"]
-            assert result["locked"]["chunks_free"] >= 0
-            assert result["locked"]["chunks_used"] >= 0
-            assert result["locked"]["free"] >= 0
-            assert result["locked"]["locked"] >= 0
-            assert result["locked"]["total"] >= 0
-            assert result["locked"]["used"] >= 0
+            self.assertIn("locked", result)
+            self.assertIn("chunks_free", result["locked"])
+            self.assertIn("chunks_used", result["locked"])
+            self.assertIn("free", result["locked"])
+            self.assertIn("locked", result["locked"])
+            self.assertIn("total", result["locked"])
+            self.assertIn("used", result["locked"])
+            self.assertTrue(result["locked"]["chunks_free"] >= 0)
+            self.assertTrue(result["locked"]["chunks_used"] >= 0)
+            self.assertTrue(result["locked"]["free"] >= 0)
+            self.assertTrue(result["locked"]["locked"] >= 0)
+            self.assertTrue(result["locked"]["total"] >= 0)
+            self.assertTrue(result["locked"]["used"] >= 0)
         else:
-            print(
+            self.log(
                 f"Skiping test: 'getmemoryinfo stats' not implemented for '{sys.platform}'"
             )
 
@@ -89,9 +90,9 @@ def test_mode_mallocinfo_ibd(self, node):
                 r"</malloc>"
             )
             result = node.get_memoryinfo("mallocinfo")
-            assert re.fullmatch(pattern, result)
+            self.assertMatch(result, pattern)
         else:
-            print(
+            self.log(
                 f"Skiping test: 'getmemoryinfo malloc' not implemented for '{sys.platform}'"
             )
 
diff --git a/tests/floresta-cli/getpeerinfo-test.py b/tests/floresta-cli/getpeerinfo-test.py
index 284fd6650..9e8b85d1c 100644
--- a/tests/floresta-cli/getpeerinfo-test.py
+++ b/tests/floresta-cli/getpeerinfo-test.py
@@ -4,8 +4,8 @@
 This functional test cli utility to interact with a Floresta node with `getpeerinfo`
 """
 
-from test_framework.test_framework import FlorestaTestFramework
 from test_framework.floresta_rpc import REGTEST_RPC_SERVER, JSONRPCError
+from test_framework.test_framework import FlorestaTestFramework
 
 
 class GetPeerInfoTest(FlorestaTestFramework):
@@ -35,15 +35,11 @@ def run_test(self):
 
         # Test assertions
         node = self.get_node(GetPeerInfoTest.nodes[0])
-        try:
-            node.get_peerinfo()
-        except JSONRPCError as exc:
-            assert exc.code == -32603
-            assert exc.data is None
-            assert exc.message == GetPeerInfoTest.expected_error
-        finally:
-            # Shutdown node
-            self.stop_node(GetPeerInfoTest.nodes[0])
+
+        result = node.get_peerinfo()
+        self.assertIsSome(result)
+        self.assertEqual(len(result), 0)
+        self.stop_node(GetPeerInfoTest.nodes[0])
 
 
 if __name__ == "__main__":
diff --git a/tests/floresta-cli/getroots-test.py b/tests/floresta-cli/getroots-test.py
index f6595bbae..21f27def8 100644
--- a/tests/floresta-cli/getroots-test.py
+++ b/tests/floresta-cli/getroots-test.py
@@ -4,8 +4,8 @@
 This functional test cli utility to interact with a Floresta node with `getroots`
 """
 
-from test_framework.test_framework import FlorestaTestFramework
 from test_framework.floresta_rpc import REGTEST_RPC_SERVER
+from test_framework.test_framework import FlorestaTestFramework
 
 
 class GetRootsIDBLenZeroTest(FlorestaTestFramework):
@@ -37,7 +37,7 @@ def run_test(self):
         # Test assertions
         node = self.get_node(GetRootsIDBLenZeroTest.nodes[0])
         vec_hashes = node.get_roots()
-        assert len(vec_hashes) == 0
+        self.assertTrue(len(vec_hashes) == 0)
 
 
 if __name__ == "__main__":
diff --git a/tests/floresta-cli/getrpcinfo-test.py b/tests/floresta-cli/getrpcinfo-test.py
index d440a330a..a768474d6 100644
--- a/tests/floresta-cli/getrpcinfo-test.py
+++ b/tests/floresta-cli/getrpcinfo-test.py
@@ -6,8 +6,9 @@
 
 import os
 import tempfile
-from test_framework.test_framework import FlorestaTestFramework
+
 from test_framework.floresta_rpc import REGTEST_RPC_SERVER
+from test_framework.test_framework import FlorestaTestFramework
 
 
 class GetRpcInfoTest(FlorestaTestFramework):
@@ -43,15 +44,18 @@ def test_rpcinfo_result(self, node):
         Test if the 'getrpcinfo' result was built correctly
         """
         result = node.get_rpcinfo()
-        assert "active_commands" in result
-        assert "logpath" in result
-        assert len(result["active_commands"]) == 1
-        assert "duration" in result["active_commands"][0]
-        assert "method" in result["active_commands"][0]
-        assert result["active_commands"][0]["duration"] == 0
-        assert result["active_commands"][0]["method"] == "getrpcinfo"
-        assert result["logpath"] == os.path.normpath(
-            os.path.join(GetRpcInfoTest.data_dir, "regtest", "output.log")
+        self.assertIn("active_commands", result)
+        self.assertIn("logpath", result)
+        self.assertEqual(len(result["active_commands"]), 1)
+        self.assertIn("duration", result["active_commands"][0])
+        self.assertIn("method", result["active_commands"][0])
+        self.assertEqual(result["active_commands"][0]["duration"], 0)
+        self.assertEqual(result["active_commands"][0]["method"], "getrpcinfo")
+        self.assertEqual(
+            result["logpath"],
+            os.path.normpath(
+                os.path.join(GetRpcInfoTest.data_dir, "regtest", "output.log")
+            ),
         )
 
     def run_test(self):
diff --git a/tests/floresta-cli/stop-test.py b/tests/floresta-cli/stop-test.py
index 6af166011..7590ae58c 100644
--- a/tests/floresta-cli/stop-test.py
+++ b/tests/floresta-cli/stop-test.py
@@ -4,8 +4,8 @@
 This functional test cli utility to interact with a Floresta node with `stop`
 """
 
-from test_framework.test_framework import FlorestaTestFramework
 from test_framework.floresta_rpc import REGTEST_RPC_SERVER
+from test_framework.test_framework import FlorestaTestFramework
 
 
 class StopTest(FlorestaTestFramework):
@@ -36,7 +36,7 @@ def run_test(self):
         result = node.stop()
 
         # node should be finished, do not call stop_node
-        assert result
+        self.assertEqual(result, "florestad stopping")
 
 
 if __name__ == "__main__":
diff --git a/tests/floresta-cli/uptime-test.py b/tests/floresta-cli/uptime-test.py
index ae658b8a8..d2cc025b4 100644
--- a/tests/floresta-cli/uptime-test.py
+++ b/tests/floresta-cli/uptime-test.py
@@ -5,10 +5,11 @@
 """
 
 import os
-import time
 import tempfile
-from test_framework.test_framework import FlorestaTestFramework
+import time
+
 from test_framework.floresta_rpc import REGTEST_RPC_SERVER
+from test_framework.test_framework import FlorestaTestFramework
 
 
 class UptimeTest(FlorestaTestFramework):
@@ -64,7 +65,7 @@ def run_test(self):
         after = time.time()
         elapsed = int(after - before)
 
-        assert uptime == elapsed
+        self.assertEqual(uptime, elapsed)
 
         # Stop node
         self.stop_node(UptimeTest.nodes[0])
diff --git a/tests/florestad/restart-test.py b/tests/florestad/restart-test.py
index 5abb71301..9b207e94e 100644
--- a/tests/florestad/restart-test.py
+++ b/tests/florestad/restart-test.py
@@ -6,12 +6,13 @@
 The directories used between each power-on/power-off must not be corrupted.
 """
 
-import time
-import os
 import filecmp
+import os
 import tempfile
-from test_framework.test_framework import FlorestaTestFramework
+import time
+
 from test_framework.floresta_rpc import REGTEST_RPC_SERVER
+from test_framework.test_framework import FlorestaTestFramework
 
 
 class TestRestart(FlorestaTestFramework):
@@ -65,7 +66,9 @@ def run_test(self):
         self.stop_node(TestRestart.indexes[1])
 
         # check for any corruption
-        assert filecmp.dircmp(TestRestart.data_dirs[0], TestRestart.data_dirs[1])
+        # if any files are different, we will get a list of them
+        result = filecmp.dircmp(TestRestart.data_dirs[0], TestRestart.data_dirs[1])
+        self.assertEqual(len(result.diff_files), 0)
 
 
 if __name__ == "__main__":
diff --git a/tests/florestad/ssl-fail-test.py b/tests/florestad/ssl-fail-test.py
index 55dfa501e..ad51fec10 100644
--- a/tests/florestad/ssl-fail-test.py
+++ b/tests/florestad/ssl-fail-test.py
@@ -38,11 +38,10 @@ def run_test(self):
 
         # now try create a connection with an electrum client at default port
         # it must fail, since the TLS port isnt opened
-        try:
+        with self.assertRaises(ConnectionRefusedError) as exc:
             TestSslFailInitialization.electrum = ElectrumClient("0.0.0.0", 50002)
 
-        except ConnectionRefusedError as exc:
-            assert exc.errno == errno.ECONNREFUSED
+        self.assertEqual(exc.exception.errno, errno.ECONNREFUSED)
 
         # Shutdown node
         self.stop_node(TestSslFailInitialization.nodes[0])
diff --git a/tests/florestad/ssl-test.py b/tests/florestad/ssl-test.py
index 655df6728..33ccd5537 100644
--- a/tests/florestad/ssl-test.py
+++ b/tests/florestad/ssl-test.py
@@ -39,9 +39,9 @@ def run_test(self):
 
         # request something to TLS port
         result = TestSslInitialization.electrum.ping()
-        self.log(result)
 
-        assert result is not None
+        # if pinged, we should get a response `""`
+        self.assertEqual(result, "")
 
         # Shutdown node
         self.stop_node(TestSslInitialization.nodes[0])
diff --git a/tests/test_framework/floresta_rpc.py b/tests/test_framework/floresta_rpc.py
index a541ef698..0d1fbb0ff 100644
--- a/tests/test_framework/floresta_rpc.py
+++ b/tests/test_framework/floresta_rpc.py
@@ -14,6 +14,8 @@
 - get_roots: `getroots`;
 """
 
+import json
+
 # commented unused modules since maybe they can be useful
 # import os
 # import shutil
@@ -22,9 +24,10 @@
 # import traceback
 import re
 import time
-import json
 from subprocess import Popen
-from requests import post, exceptions
+from typing import Any
+
+from requests import exceptions, post
 
 REGTEST_RPC_SERVER = {
     "host": "127.0.0.1",
@@ -165,7 +168,7 @@ def wait_to_stop(self):
         else:
             raise RuntimeError("Cannot wait for null process")
 
-    def perform_request(self, method, params=None) -> dict:
+    def perform_request(self, method, params=None) -> Any:
         """
         Perform an JsonRPC request to the floresta node.
         """
diff --git a/tests/test_framework/test_framework.py b/tests/test_framework/test_framework.py
index 0eabe49ff..f86ea5e4f 100644
--- a/tests/test_framework/test_framework.py
+++ b/tests/test_framework/test_framework.py
@@ -4,22 +4,22 @@
 Adapted from
 https://github.com/bitcoin/bitcoin/blob/master/test/functional/test_framework/test_framework.py
 
-BitcoinCore functional tests define a metaclass that checks if some important methods are defined
-or not defined.
-
-Floresta functional tests will follow this since it is a good practice for a framework.
-
-The difference is that our node will run withing a `cargo run` subprocess, defined at
-`add_node_settings`.
+BitcoinCore functional tests define a metaclass that checks if some important
+methods are defined or not defined. Floresta functional tests will follow this
+since it is a good practice for a framework. The difference is that our node
+will run withing a `cargo run` subprocess, defined at `add_node_settings`.
 """
 
 import os
+import re
 import subprocess
-from test_framework.floresta_rpc import FlorestaRPC
+from typing import Any, List, Pattern
+
 from test_framework.crypto.pkcs8 import (
     create_pkcs8_private_key,
     create_pkcs8_self_signed_certificate,
 )
+from test_framework.floresta_rpc import FlorestaRPC
 
 VALID_FLORESTAD_EXTRA_ARGS = [
     "-c",
@@ -76,15 +76,73 @@ def __new__(mcs, clsname, bases, dct):
         return super().__new__(mcs, clsname, bases, dct)
 
 
+# pylint: disable=too-many-public-methods
 class FlorestaTestFramework(metaclass=FlorestaTestMetaClass):
     """
-    Base class for a floresta test script.
+    Base class for a floresta test script. Individual floresta
+    test scripts should:
+
+    - subclass FlorestaTestFramework;
+    - not override the __init__() method;
+    - not override the main() method;
+    - implement set_test_params();
+    - implement run_test();
+
+    The `set_test_params` method is called before the test starts
+    and aims to configure nodes, florestad params, what should be
+    considered as expected result, and what you think should be defined.
+    It is a good practice to set the number of nodes and their
+    configuration in this method with `self.add_node_settings`.
+
+    The `run_test` method is the test itself, where a (or more) node(s)
+    are started, and the test is executed. This is where you start a node
+    with `run_node` and wait for it to be ready with `wait_for_rpc_connection`.
+    It is also where you should do the assertions (`self.assertIsNone`,
+    `self.assertIsSome`, `self.assertEqual`, `self.assertIn`,
+    `self.assertMatch`, `self.assertTrue`, `self.assertRaises`)
+    as well stop nodes when done (`self.stop_node` for stop one node
+    or `self.stop` to stop all nodes).
+
+    In both mthods, you can use `self.log` to log messages.
+
+    At the end of file, you should execute `MyTest().main()` method.
+
+    For more details, see the tests/example/example-test.py and/or
+    tests/test_framework/test_framework.py.
+    """
+
+    class _AssertRaisesContext:
+        """
+        Context manager for testing that an exception is raised.
+
+        This keeps the assertRaises functionality neatly contained within our test framework
+        """
 
-    Individual floresta test scripts should subclass this class and override the:
+        def __init__(self, test_framework, expected_exception):
+            """Initialize the context manager with the expected exception type."""
+            self.test_framework = test_framework
+            self.expected_exception = expected_exception
+            self.exception = None
 
-    - set_test_params(); and
-    - run_test() methods.
-    """
+        def __enter__(self):
+            """Enter the context manager."""
+            return self
+
+        def __exit__(self, exc_type, exc_value, traceback):
+            """Exit the context manager and check if the expected exception was raised."""
+            if exc_type is None:
+                self.test_framework.stop_all_nodes()
+                trace = traceback.format_exc()
+                message = f"{self.expected_exception} was not raised"
+                raise AssertionError(f"{message}: {trace}")
+
+            if not issubclass(exc_type, self.expected_exception):
+                trace = traceback.format_exc()
+                message = f"Expected {self.expected_exception} but got {exc_type}"
+                raise AssertionError(f"{message}: {trace}")
+
+            self.exception = exc_value
+            return True
 
     def __init__(self):
         """
@@ -95,7 +153,7 @@ def __init__(self):
         self._tests = []
         self._nodes = []
 
-    def log(self, msg: str) -> str:
+    def log(self, msg: str):
         """Log a message with the class caller"""
         print(f"[{self.__class__.__name__} INFO] {msg}")
 
@@ -128,37 +186,29 @@ def get_integration_test_dir():
         Get path for florestad used in integration tests, generally set on
         $FLORESTA_TEMP_DIR/binaries
         """
+        if os.getenv("FLORESTA_TEMP_DIR") is None:
+            raise RuntimeError(
+                "FLORESTA_TEMP_DIR not set. "
+                + " Please set it to the path of the integration test directory."
+            )
         return os.path.normpath(
-            os.path.join(os.environ.get("FLORESTA_TEMP_DIR"), "binaries")
+            os.path.join(os.getenv("FLORESTA_TEMP_DIR"), "binaries")
         )
 
-    @staticmethod
-    def get_target_release_dir():
-        """ "
-        Get path for built florestad, generally on
-        ./target/release/florestad
-        """
-        dirname = os.path.dirname(__file__)
-        return os.path.normpath(os.path.join(dirname, "..", "..", "target", "release"))
-
     def create_ssl_keys(self) -> tuple[str, str]:
         """
         Create a PKCS#8 formatted private key and a self-signed certificate.
         These keys are intended to be used with florestad's --ssl-key-path and --ssl-cert-path
         options.
         """
-        # Check if we're in CI or not
-        if "/tmp/floresta-integration-tests" in os.getenv("PATH"):
-            ssl_path = os.path.normpath(
-                os.path.abspath(
-                    os.path.join(self.get_integration_test_dir(), "..", "..", "ssl")
-                )
-            )
-        else:
-            home = os.path.expanduser("~")  # Fixed: '~user' -> '~' for current user
-            ssl_path = os.path.normpath(
-                os.path.abspath(os.path.join(home, ".floresta", "ssl"))
-            )
+        # If we're in CI, we need to use the
+        # path to the integration test dir
+        # tempfile will be used to get the proper
+        # temp dir for the OS
+        ssl_rel_path = os.path.join(
+            FlorestaTestFramework.get_integration_test_dir(), "..", "..", "ssl"
+        )
+        ssl_path = os.path.normpath(os.path.abspath(ssl_rel_path))
 
         # Create the folder if not exists
         os.makedirs(ssl_path, exist_ok=True)
@@ -179,32 +229,29 @@ def add_node_settings(
         self, chain: str, extra_args: list[str], rpcserver: dict, ssl: bool = False
     ) -> int:
         """
-        Add a node settings to be run. Use this on set_test_params method many times you want.
-
-        extra_args should be a list of string in the --key=value strings
-        (see florestad --help for a list of available commands)
+        Add a node settings to be run. Use this on set_test_params method
+        many times you want. Extra_args should be a list of string in the
+        --key=value strings (see florestad --help for a list of available
+        commands)
         """
         # PR #331 introduced a preparatory environment at
         # /tmp/floresta-integration-tests.$(git rev-parse HEAD).
-        tmpdir = FlorestaTestFramework.get_integration_test_dir()
-        targetdir = FlorestaTestFramework.get_target_release_dir()
-
         # So, check for it first before define the florestad path.
-        if os.path.exists(tmpdir):
-            florestad = os.path.normpath(os.path.join(tmpdir, "florestad"))
-
-        # If not exists, define the one at ./target/release.
-        elif os.path.exists(targetdir):
-            florestad = os.path.normpath(os.path.join(targetdir, "florestad"))
+        if os.getenv("FLORESTA_TEMP_DIR") is not None:
+            targetdir = FlorestaTestFramework.get_integration_test_dir()
 
-        # In case any test florestad is found, raise an exception
         else:
             raise RuntimeError(
-                f"Not found 'florestad' in '{tmpdir}' or '{targetdir}'. "
-                "Run 'tests/prepare.sh' or 'cargo build --release'."
+                "FLORESTA_TEMP_DIR not set. "
+                + " Please set it to the path of the integration test directory."
             )
 
-        print(f"Using {florestad}")
+        florestad = os.path.join(targetdir, "florestad")
+
+        # In case any florestad is found, raise an exception
+        if not os.path.exists(florestad):
+            raise RuntimeError(f"Not found any 'florestad' in '{targetdir}'")
+
         setting = {
             "chain": chain,
             "config": [florestad, "--network", chain],
@@ -258,7 +305,8 @@ def run_node(self, index: int):
 
         if node["chain"] == "regtest":
             # pylint: disable=consider-using-with
-            # add text=True to treat all outputs as texts (jsons or python stack traces)
+            # add text=True to treat all outputs as texts
+            # (jsons or python stack traces)
             cmd = " ".join(node["config"])
             self.log(f"Running '{cmd}'")
             process_node = subprocess.Popen(node["config"], text=True)
@@ -296,3 +344,80 @@ def stop(self):
         """
         for i in range(len(self._nodes)):
             self.stop_node(i)
+
+    # pylint: disable=invalid-name
+    def assertTrue(self, condition: bool):
+        """
+        Assert if the condition is True, otherwise
+        all nodes will be stopped and an AssertionError will
+        be raised
+        """
+        if not condition:
+            self.stop()
+            raise AssertionError(f"Actual: {condition}\nExpected: True")
+
+    # pylint: disable=invalid-name
+    def assertIsNone(self, thing: Any):
+        """
+        Assert if the condition is None, otherwise
+        all nodes will be stopped and an AssertionError will
+        be raised
+        """
+        if thing is not None:
+            self.stop()
+            raise AssertionError(f"Actual: {thing}\nExpected: None")
+
+    # pylint: disable=invalid-name
+    def assertIsSome(self, thing: Any):
+        """
+        Assert if the condition is not None, otherwise
+        all nodes will be stopped and an AssertionError will
+        be raised
+        """
+        if thing is None:
+            self.stop()
+            raise AssertionError(f"Actual: {thing}\nExpected: not None")
+
+    # pylint: disable=invalid-name
+    def assertEqual(self, condition: Any, expected: Any):
+        """
+        Assert if the condition is True, otherwise
+        all nodes will be stopped and an AssertionError will
+        be raised
+        """
+
+        if not condition == expected:
+            self.stop()
+            raise AssertionError(f"Actual: {condition}\nExpected: {expected}")
+
+    # pylint: disable=invalid-name
+    def assertIn(self, element: Any, listany: List[Any]):
+        """
+        Assert if the element is in listany , otherwise
+        all nodes will be stopped and an AssertionError will
+        be raised
+        """
+
+        if element not in listany:
+            self.stop()
+            raise AssertionError(
+                f"Actual: {element} not in {listany}\nExpected: {element} in {listany}"
+            )
+
+    # pylint: disable=invalid-name
+    def assertMatch(self, actual: Any, pattern: Pattern):
+        """
+        Assert if the element fully matches a pattern, otherwise
+        all nodes will be stopped and an AssertionError will
+        be raised
+        """
+
+        if not re.fullmatch(pattern, actual):
+            self.stop()
+            raise AssertionError(
+                f"Actual: {actual} !~ {pattern} \nExpected: {actual} ~ {set}"
+            )
+
+    def assertRaises(self, expected_exception):
+        """Assert that the expected exception is raised."""
+        return self._AssertRaisesContext(self, expected_exception)


Reviews:
user: login: Davidson-Souza
body: I like the changes, just a few comments.
state: CHANGES_REQUESTED
author_association: MEMBER
submitted_at: 2025-03-31T18:08:57Z
user: login: qlrd
state: COMMENTED
author_association: CONTRIBUTOR
submitted_at: 2025-04-01T19:28:43Z
user: login: qlrd
state: COMMENTED
author_association: CONTRIBUTOR
submitted_at: 2025-04-01T19:51:00Z
user: login: qlrd
state: COMMENTED
author_association: CONTRIBUTOR
submitted_at: 2025-04-02T12:18:34Z
user: login: qlrd
state: COMMENTED
author_association: CONTRIBUTOR
submitted_at: 2025-04-02T16:48:09Z
user: login: jaoleal
state: COMMENTED
author_association: MEMBER
submitted_at: 2025-04-03T14:30:57Z
user: login: Davidson-Souza
state: COMMENTED
author_association: MEMBER
submitted_at: 2025-04-03T15:52:56Z
user: login: qlrd
state: COMMENTED
author_association: CONTRIBUTOR
submitted_at: 2025-04-04T16:56:38Z
user: login: qlrd
state: COMMENTED
author_association: CONTRIBUTOR
submitted_at: 2025-04-04T18:05:58Z
user: login: qlrd
state: COMMENTED
author_association: CONTRIBUTOR
submitted_at: 2025-04-06T19:30:32Z
user: login: qlrd
state: COMMENTED
author_association: CONTRIBUTOR
submitted_at: 2025-04-06T19:31:51Z
user: login: jaoleal
state: COMMENTED
author_association: MEMBER
submitted_at: 2025-04-08T13:18:53Z
user: login: qlrd
state: COMMENTED
author_association: CONTRIBUTOR
submitted_at: 2025-04-08T13:29:48Z
user: login: qlrd
state: COMMENTED
author_association: CONTRIBUTOR
submitted_at: 2025-04-08T17:36:39Z
user: login: jaoleal
body: LGTM, just a thing:
state: CHANGES_REQUESTED
author_association: MEMBER
submitted_at: 2025-04-08T19:09:15Z
user: login: qlrd
state: COMMENTED
author_association: CONTRIBUTOR
submitted_at: 2025-04-08T19:28:08Z
user: login: qlrd
state: COMMENTED
author_association: CONTRIBUTOR
submitted_at: 2025-04-09T11:45:33Z
user: login: jaoleal
body: c`ACK`, could you squash the commits ?
state: APPROVED
author_association: MEMBER
submitted_at: 2025-04-09T13:38:12Z
user: login: Davidson-Souza
body: Just one tiny thing and we are good
state: COMMENTED
author_association: MEMBER
submitted_at: 2025-04-10T16:45:56Z
user: login: qlrd
state: COMMENTED
author_association: CONTRIBUTOR
submitted_at: 2025-04-11T10:36:56Z
user: login: Davidson-Souza
body: ACK [bcb64d5](https://github.com/vinteumorg/Floresta/commit/bcb64d57bc590ae27f0fad76e8e586e390f39cd1)
state: APPROVED
author_association: MEMBER
submitted_at: 2025-04-11T15:05:14Z
user: login: jaoleal
state: APPROVED
author_association: MEMBER
submitted_at: 2025-04-11T15:12:37Z

Review comments:
diff_hunk: @@ -296,3 +342,58 @@ def stop(self):
         """
         for i in range(len(self._nodes)):
             self.stop_node(i)
+
+    # pylint: disable=invalid-name
+    def assertTrue(self, condition: bool):
+        """
+        Assert if the condition is True, otherwise
+        all nodes will be stopped and an AssertionError will
+        be raised
+        """
+        if not condition:
+            self.stop()
+            raise AssertionError(f"Actual: {condition}\nExpected: True")
+
+    # pylint: disable=invalid-name
+    def assertEqual(self, condition: Any, expected: Any):
+        """
+        Assert if the condition is True, otherwise
+        all nodes will be stopped and an AssertionError will
+        be raised
+        """
+
+        if not condition == expected:
+            self.stop()
+            raise AssertionError(f"Actual: {condition}\nExpected: {expected}")
+
+    # pylint: disable=invalid-name
+    def assertIn(self, element: Any, listany: List[Any]):
+        """
+        Assert if the element is in listany , otherwise
+        all nodes will be stopped and an AssertionError will
+        be raised
+        """
+
+        if element not in listany:
+            self.stop()
+            raise AssertionError(
+                f"Actual: {element} not in {listany}\nExpected: {element} in {listany}"
+            )
+
+    # pylint: disable=invalid-name
+    def assertMatch(self, actual: Any, pattern: Pattern):
+        """
+        Assert if the element is in set , otherwise
path: tests/test_framework/test_framework.py
user: login: Davidson-Souza
body: d5a044650e73474fd8d3752e1641f40e8349b60b

nit: Asset if the element fully matches a pattern. No?
created_at: 2025-03-31T17:22:04Z
author_association: MEMBER
diff_hunk: @@ -90,11 +91,11 @@ def run_test(self):
         try:
             node = self.get_node(GetAddnodeIDBErrorTest.nodes[0])
             success = node.get_addnode(node="0.0.0.0:18443")
-            assert success
+            self.assertTrue(success is not None)
path: tests/floresta-cli/addnode-test.py
user: login: Davidson-Souza
body: ac7166db54c3b0d3fd43c8d17ab49959f15c32be

Maybe make a `assertIsSome`? 
created_at: 2025-03-31T17:24:34Z
author_association: MEMBER
diff_hunk: @@ -37,7 +37,7 @@ def run_test(self):
         # Test assertions
         node = self.get_node(GetRootsIDBLenZeroTest.nodes[0])
         vec_hashes = node.get_roots()
-        assert len(vec_hashes) == 0
+        self.assertTrue(len(vec_hashes) == 0)
path: tests/floresta-cli/getroots-test.py
user: login: Davidson-Souza
body: ac7166d

`assertEq`
created_at: 2025-03-31T18:02:16Z
author_association: MEMBER
diff_hunk: @@ -296,3 +342,58 @@ def stop(self):
         """
         for i in range(len(self._nodes)):
             self.stop_node(i)
+
+    # pylint: disable=invalid-name
+    def assertTrue(self, condition: bool):
path: tests/test_framework/test_framework.py
user: login: Davidson-Souza
body: d5a044650e73474fd8d3752e1641f40e8349b60b

I think this could be called just `assert`. 
created_at: 2025-03-31T18:03:55Z
author_association: MEMBER
diff_hunk: @@ -80,12 +83,55 @@ class FlorestaTestFramework(metaclass=FlorestaTestMetaClass):
     """
     Base class for a floresta test script.
 
-    Individual floresta test scripts should subclass this class and override the:
-
-    - set_test_params(); and
-    - run_test() methods.
+    * should call the main() method to run the test;
path: tests/test_framework/test_framework.py
user: login: Davidson-Souza
body: d5a044650e73474fd8d3752e1641f40e8349b60b

Who needs to do this :joy:? I think this comment is missing the first line that was removed, or something like this.
created_at: 2025-03-31T18:08:28Z
author_association: MEMBER
diff_hunk: @@ -296,3 +342,58 @@ def stop(self):
         """
         for i in range(len(self._nodes)):
             self.stop_node(i)
+
+    # pylint: disable=invalid-name
+    def assertTrue(self, condition: bool):
path: tests/test_framework/test_framework.py
user: login: qlrd
body: `assert` is a reserved word, so both lint and compiler won't let it be defined like that.
created_at: 2025-04-01T19:28:42Z
author_association: CONTRIBUTOR
diff_hunk: @@ -80,12 +83,55 @@ class FlorestaTestFramework(metaclass=FlorestaTestMetaClass):
     """
     Base class for a floresta test script.
 
-    Individual floresta test scripts should subclass this class and override the:
-
-    - set_test_params(); and
-    - run_test() methods.
+    * should call the main() method to run the test;
path: tests/test_framework/test_framework.py
user: login: qlrd
body: Thanks! It's a bad habit of mine to forget the subject in the sentence.
created_at: 2025-04-01T19:51:00Z
author_association: CONTRIBUTOR
diff_hunk: @@ -90,11 +91,11 @@ def run_test(self):
         try:
             node = self.get_node(GetAddnodeIDBErrorTest.nodes[0])
             success = node.get_addnode(node="0.0.0.0:18443")
-            assert success
+            self.assertTrue(success is not None)
path: tests/floresta-cli/addnode-test.py
user: login: qlrd
body: Nice, i will add it too
created_at: 2025-04-02T12:18:34Z
author_association: CONTRIBUTOR
diff_hunk: @@ -90,11 +91,11 @@ def run_test(self):
         try:
             node = self.get_node(GetAddnodeIDBErrorTest.nodes[0])
             success = node.get_addnode(node="0.0.0.0:18443")
-            assert success
+            self.assertTrue(success is not None)
path: tests/floresta-cli/addnode-test.py
user: login: qlrd
body: Creating a `assertIsNone` and a `assertIsSome`
created_at: 2025-04-02T16:48:09Z
author_association: CONTRIBUTOR
diff_hunk: @@ -76,15 +77,70 @@ def __new__(mcs, clsname, bases, dct):
         return super().__new__(mcs, clsname, bases, dct)
 
 
+# pylint: disable=too-many-public-methods
 class FlorestaTestFramework(metaclass=FlorestaTestMetaClass):
     """
-    Base class for a floresta test script.
+    Base class for a floresta test script. Individual floresta
+    test scripts should subclass this class and:
+
+    - should subclass FlorestaTestFramework;
+    - should not override the __init__() method;
+    - should not override the main() method;
+    - should implement set_test_params();
+    - should implement run_test();
+
+    Additionally, the test script could add some methods in either
+    in set_test_params() or run_test():
+
+    - log() method to log messages;
+    - add_node_settings() method to add a node settings;
+    - run_node() method to run a node;
+    - get_node() method to get a node;
+    - wait_for_rpc_connection() method to wait for a node to be ready;
+    - create_ssl_keys() method to create SSL keys;
+    - assertTrue() method to assert a condition is True;
+    - assertEqual() method to assert two values are equal;
+    - assertIn() method to assert a value is in a list;
+    - assertMatch() method to assert a value matches a regex;
+    - assertRaises() method to assert an exception is raised;
+    - assertIsSome() method to assert a value is not None;
path: tests/test_framework/test_framework.py
user: login: jaoleal
body: This docs are actually just repeating the name of the functions.

IMO they could be better explained
created_at: 2025-04-03T14:07:16Z
author_association: MEMBER
diff_hunk: @@ -179,32 +240,27 @@ def add_node_settings(
         self, chain: str, extra_args: list[str], rpcserver: dict, ssl: bool = False
     ) -> int:
         """
-        Add a node settings to be run. Use this on set_test_params method many times you want.
-
-        extra_args should be a list of string in the --key=value strings
-        (see florestad --help for a list of available commands)
+        Add a node settings to be run. Use this on set_test_params method
+        many times you want. Extra_args should be a list of string in the
+        --key=value strings (see florestad --help for a list of available
+        commands)
         """
         # PR #331 introduced a preparatory environment at
         # /tmp/floresta-integration-tests.$(git rev-parse HEAD).
-        tmpdir = FlorestaTestFramework.get_integration_test_dir()
-        targetdir = FlorestaTestFramework.get_target_release_dir()
-
         # So, check for it first before define the florestad path.
-        if os.path.exists(tmpdir):
-            florestad = os.path.normpath(os.path.join(tmpdir, "florestad"))
+        if os.getenv("FLORESTA_TEMP_DIR") is not None:
+            targetdir = FlorestaTestFramework.get_integration_test_dir()
 
         # If not exists, define the one at ./target/release.
-        elif os.path.exists(targetdir):
-            florestad = os.path.normpath(os.path.join(targetdir, "florestad"))
-
-        # In case any test florestad is found, raise an exception
         else:
-            raise RuntimeError(
-                f"Not found 'florestad' in '{tmpdir}' or '{targetdir}'. "
-                "Run 'tests/prepare.sh' or 'cargo build --release'."
-            )
+            targetdir = FlorestaTestFramework.get_target_release_dir()
+
+        florestad = os.path.join(targetdir, "florestad")
+
+        # In case any florestad is found, raise an exception
+        if not os.path.exists(florestad):
path: tests/test_framework/test_framework.py
user: login: jaoleal
body: Raise an exception if it doenst find `$FLORESTA_TEMP_DIR`, getting binaries from the default build path will induce version conflicts
created_at: 2025-04-03T14:15:01Z
author_association: MEMBER
diff_hunk: @@ -179,32 +240,27 @@ def add_node_settings(
         self, chain: str, extra_args: list[str], rpcserver: dict, ssl: bool = False
     ) -> int:
         """
-        Add a node settings to be run. Use this on set_test_params method many times you want.
-
-        extra_args should be a list of string in the --key=value strings
-        (see florestad --help for a list of available commands)
+        Add a node settings to be run. Use this on set_test_params method
+        many times you want. Extra_args should be a list of string in the
+        --key=value strings (see florestad --help for a list of available
+        commands)
         """
         # PR #331 introduced a preparatory environment at
         # /tmp/floresta-integration-tests.$(git rev-parse HEAD).
-        tmpdir = FlorestaTestFramework.get_integration_test_dir()
-        targetdir = FlorestaTestFramework.get_target_release_dir()
-
         # So, check for it first before define the florestad path.
-        if os.path.exists(tmpdir):
-            florestad = os.path.normpath(os.path.join(tmpdir, "florestad"))
+        if os.getenv("FLORESTA_TEMP_DIR") is not None:
+            targetdir = FlorestaTestFramework.get_integration_test_dir()
 
         # If not exists, define the one at ./target/release.
-        elif os.path.exists(targetdir):
-            florestad = os.path.normpath(os.path.join(targetdir, "florestad"))
-
-        # In case any test florestad is found, raise an exception
         else:
-            raise RuntimeError(
-                f"Not found 'florestad' in '{tmpdir}' or '{targetdir}'. "
-                "Run 'tests/prepare.sh' or 'cargo build --release'."
-            )
+            targetdir = FlorestaTestFramework.get_target_release_dir()
+
+        florestad = os.path.join(targetdir, "florestad")
+
+        # In case any florestad is found, raise an exception
+        if not os.path.exists(florestad):
path: tests/test_framework/test_framework.py
user: login: jaoleal
body: Focus all temporary things thats needed by tests, like logs, test builds  (the `create_ssl_keys` function for example, it store things on `tempdir` instead of `$FLORESTA_TEMP_DIR`) inside `$FLORESTA_TEMP_DIR` so we have more control about what our tests needs to run.
created_at: 2025-04-03T14:28:00Z
author_association: MEMBER
diff_hunk: @@ -38,9 +38,9 @@ def run_test(self):
         try:
             node.get_peerinfo()
         except JSONRPCError as exc:
-            assert exc.code == -32603
-            assert exc.data is None
-            assert exc.message == GetPeerInfoTest.expected_error
+            self.assertEqual(exc.code, -32603)
+            self.assertTrue(exc.data is None)
path: tests/floresta-cli/getpeerinfo-test.py
user: login: Davidson-Souza
body: c021bc7ca29d1f76eb0279428e334f9aff8b8319

You have a method for this
created_at: 2025-04-03T15:52:56Z
author_association: MEMBER
diff_hunk: @@ -90,11 +91,11 @@ def run_test(self):
         try:
             node = self.get_node(GetAddnodeIDBErrorTest.nodes[0])
             success = node.get_addnode(node="0.0.0.0:18443")
-            assert success
+            self.assertTrue(success is not None)
path: tests/floresta-cli/addnode-test.py
user: login: qlrd
body: Fixed
created_at: 2025-04-04T16:56:38Z
author_association: CONTRIBUTOR
diff_hunk: @@ -179,32 +240,27 @@ def add_node_settings(
         self, chain: str, extra_args: list[str], rpcserver: dict, ssl: bool = False
     ) -> int:
         """
-        Add a node settings to be run. Use this on set_test_params method many times you want.
-
-        extra_args should be a list of string in the --key=value strings
-        (see florestad --help for a list of available commands)
+        Add a node settings to be run. Use this on set_test_params method
+        many times you want. Extra_args should be a list of string in the
+        --key=value strings (see florestad --help for a list of available
+        commands)
         """
         # PR #331 introduced a preparatory environment at
         # /tmp/floresta-integration-tests.$(git rev-parse HEAD).
-        tmpdir = FlorestaTestFramework.get_integration_test_dir()
-        targetdir = FlorestaTestFramework.get_target_release_dir()
-
         # So, check for it first before define the florestad path.
-        if os.path.exists(tmpdir):
-            florestad = os.path.normpath(os.path.join(tmpdir, "florestad"))
+        if os.getenv("FLORESTA_TEMP_DIR") is not None:
+            targetdir = FlorestaTestFramework.get_integration_test_dir()
 
         # If not exists, define the one at ./target/release.
-        elif os.path.exists(targetdir):
-            florestad = os.path.normpath(os.path.join(targetdir, "florestad"))
-
-        # In case any test florestad is found, raise an exception
         else:
-            raise RuntimeError(
-                f"Not found 'florestad' in '{tmpdir}' or '{targetdir}'. "
-                "Run 'tests/prepare.sh' or 'cargo build --release'."
-            )
+            targetdir = FlorestaTestFramework.get_target_release_dir()
+
+        florestad = os.path.join(targetdir, "florestad")
+
+        # In case any florestad is found, raise an exception
+        if not os.path.exists(florestad):
path: tests/test_framework/test_framework.py
user: login: qlrd
body: > Raise an exception if it doenst find $FLORESTA_TEMP_DIR, getting binaries from the default build path will induce version conflicts

> Focus all temporary things thats needed by tests, like logs, test builds (the create_ssl_keys function for example, it store things on tempdir instead of $FLORESTA_TEMP_DIR) inside $FLORESTA_TEMP_DIR so we have more control about what our tests needs to run.

This make sense for CI and when user run `./tests/prepare.sh && ./tests/run.sh` (and this is what i wanted to be achieved with these changes). But there're two situations when running tests: one is when `FLORESTA_TEMP_DIR` is defined and another isnt defined.

The second one is if the user just run `uv run tests/run_tests.py` and the `FLORESTA_TEMP_DIR` will not exist, and then, the test will crash.

@Davidson-Souza, @jaoleal, there's a "middle's path"?
created_at: 2025-04-04T18:05:58Z
author_association: CONTRIBUTOR
diff_hunk: @@ -76,15 +77,70 @@ def __new__(mcs, clsname, bases, dct):
         return super().__new__(mcs, clsname, bases, dct)
 
 
+# pylint: disable=too-many-public-methods
 class FlorestaTestFramework(metaclass=FlorestaTestMetaClass):
     """
-    Base class for a floresta test script.
+    Base class for a floresta test script. Individual floresta
+    test scripts should subclass this class and:
+
+    - should subclass FlorestaTestFramework;
+    - should not override the __init__() method;
+    - should not override the main() method;
+    - should implement set_test_params();
+    - should implement run_test();
+
+    Additionally, the test script could add some methods in either
+    in set_test_params() or run_test():
+
+    - log() method to log messages;
+    - add_node_settings() method to add a node settings;
+    - run_node() method to run a node;
+    - get_node() method to get a node;
+    - wait_for_rpc_connection() method to wait for a node to be ready;
+    - create_ssl_keys() method to create SSL keys;
+    - assertTrue() method to assert a condition is True;
+    - assertEqual() method to assert two values are equal;
+    - assertIn() method to assert a value is in a list;
+    - assertMatch() method to assert a value matches a regex;
+    - assertRaises() method to assert an exception is raised;
+    - assertIsSome() method to assert a value is not None;
path: tests/test_framework/test_framework.py
user: login: qlrd
body: Changed this docstrings with more detailed information
created_at: 2025-04-06T19:30:31Z
author_association: CONTRIBUTOR
diff_hunk: @@ -38,9 +38,9 @@ def run_test(self):
         try:
             node.get_peerinfo()
         except JSONRPCError as exc:
-            assert exc.code == -32603
-            assert exc.data is None
-            assert exc.message == GetPeerInfoTest.expected_error
+            self.assertEqual(exc.code, -32603)
+            self.assertTrue(exc.data is None)
path: tests/floresta-cli/getpeerinfo-test.py
user: login: qlrd
body: fixed
created_at: 2025-04-06T19:31:51Z
author_association: CONTRIBUTOR
diff_hunk: @@ -179,32 +240,27 @@ def add_node_settings(
         self, chain: str, extra_args: list[str], rpcserver: dict, ssl: bool = False
     ) -> int:
         """
-        Add a node settings to be run. Use this on set_test_params method many times you want.
-
-        extra_args should be a list of string in the --key=value strings
-        (see florestad --help for a list of available commands)
+        Add a node settings to be run. Use this on set_test_params method
+        many times you want. Extra_args should be a list of string in the
+        --key=value strings (see florestad --help for a list of available
+        commands)
         """
         # PR #331 introduced a preparatory environment at
         # /tmp/floresta-integration-tests.$(git rev-parse HEAD).
-        tmpdir = FlorestaTestFramework.get_integration_test_dir()
-        targetdir = FlorestaTestFramework.get_target_release_dir()
-
         # So, check for it first before define the florestad path.
-        if os.path.exists(tmpdir):
-            florestad = os.path.normpath(os.path.join(tmpdir, "florestad"))
+        if os.getenv("FLORESTA_TEMP_DIR") is not None:
+            targetdir = FlorestaTestFramework.get_integration_test_dir()
 
         # If not exists, define the one at ./target/release.
-        elif os.path.exists(targetdir):
-            florestad = os.path.normpath(os.path.join(targetdir, "florestad"))
-
-        # In case any test florestad is found, raise an exception
         else:
-            raise RuntimeError(
-                f"Not found 'florestad' in '{tmpdir}' or '{targetdir}'. "
-                "Run 'tests/prepare.sh' or 'cargo build --release'."
-            )
+            targetdir = FlorestaTestFramework.get_target_release_dir()
+
+        florestad = os.path.join(targetdir, "florestad")
+
+        # In case any florestad is found, raise an exception
+        if not os.path.exists(florestad):
path: tests/test_framework/test_framework.py
user: login: jaoleal
body: >the test will crash.

Thats the intention. If one doesnt set the variable it will not run...

created_at: 2025-04-08T13:18:53Z
author_association: MEMBER
diff_hunk: @@ -179,32 +240,27 @@ def add_node_settings(
         self, chain: str, extra_args: list[str], rpcserver: dict, ssl: bool = False
     ) -> int:
         """
-        Add a node settings to be run. Use this on set_test_params method many times you want.
-
-        extra_args should be a list of string in the --key=value strings
-        (see florestad --help for a list of available commands)
+        Add a node settings to be run. Use this on set_test_params method
+        many times you want. Extra_args should be a list of string in the
+        --key=value strings (see florestad --help for a list of available
+        commands)
         """
         # PR #331 introduced a preparatory environment at
         # /tmp/floresta-integration-tests.$(git rev-parse HEAD).
-        tmpdir = FlorestaTestFramework.get_integration_test_dir()
-        targetdir = FlorestaTestFramework.get_target_release_dir()
-
         # So, check for it first before define the florestad path.
-        if os.path.exists(tmpdir):
-            florestad = os.path.normpath(os.path.join(tmpdir, "florestad"))
+        if os.getenv("FLORESTA_TEMP_DIR") is not None:
+            targetdir = FlorestaTestFramework.get_integration_test_dir()
 
         # If not exists, define the one at ./target/release.
-        elif os.path.exists(targetdir):
-            florestad = os.path.normpath(os.path.join(targetdir, "florestad"))
-
-        # In case any test florestad is found, raise an exception
         else:
-            raise RuntimeError(
-                f"Not found 'florestad' in '{tmpdir}' or '{targetdir}'. "
-                "Run 'tests/prepare.sh' or 'cargo build --release'."
-            )
+            targetdir = FlorestaTestFramework.get_target_release_dir()
+
+        florestad = os.path.join(targetdir, "florestad")
+
+        # In case any florestad is found, raise an exception
+        if not os.path.exists(florestad):
path: tests/test_framework/test_framework.py
user: login: qlrd
body: Understood! Make sense for reprodutibility.
created_at: 2025-04-08T13:29:48Z
author_association: CONTRIBUTOR
diff_hunk: @@ -179,32 +240,27 @@ def add_node_settings(
         self, chain: str, extra_args: list[str], rpcserver: dict, ssl: bool = False
     ) -> int:
         """
-        Add a node settings to be run. Use this on set_test_params method many times you want.
-
-        extra_args should be a list of string in the --key=value strings
-        (see florestad --help for a list of available commands)
+        Add a node settings to be run. Use this on set_test_params method
+        many times you want. Extra_args should be a list of string in the
+        --key=value strings (see florestad --help for a list of available
+        commands)
         """
         # PR #331 introduced a preparatory environment at
         # /tmp/floresta-integration-tests.$(git rev-parse HEAD).
-        tmpdir = FlorestaTestFramework.get_integration_test_dir()
-        targetdir = FlorestaTestFramework.get_target_release_dir()
-
         # So, check for it first before define the florestad path.
-        if os.path.exists(tmpdir):
-            florestad = os.path.normpath(os.path.join(tmpdir, "florestad"))
+        if os.getenv("FLORESTA_TEMP_DIR") is not None:
+            targetdir = FlorestaTestFramework.get_integration_test_dir()
 
         # If not exists, define the one at ./target/release.
-        elif os.path.exists(targetdir):
-            florestad = os.path.normpath(os.path.join(targetdir, "florestad"))
-
-        # In case any test florestad is found, raise an exception
         else:
-            raise RuntimeError(
-                f"Not found 'florestad' in '{tmpdir}' or '{targetdir}'. "
-                "Run 'tests/prepare.sh' or 'cargo build --release'."
-            )
+            targetdir = FlorestaTestFramework.get_target_release_dir()
+
+        florestad = os.path.join(targetdir, "florestad")
+
+        # In case any florestad is found, raise an exception
+        if not os.path.exists(florestad):
path: tests/test_framework/test_framework.py
user: login: qlrd
body: @jaoleal, fixed
created_at: 2025-04-08T17:36:39Z
author_association: CONTRIBUTOR
diff_hunk: @@ -147,17 +206,22 @@ def create_ssl_keys(self) -> tuple[str, str]:
         These keys are intended to be used with florestad's --ssl-key-path and --ssl-cert-path
         options.
         """
-        # Check if we're in CI or not
-        if "/tmp/floresta-integration-tests" in os.getenv("PATH"):
-            ssl_path = os.path.normpath(
-                os.path.abspath(
-                    os.path.join(self.get_integration_test_dir(), "..", "..", "ssl")
-                )
+        # If we're in CI, we need to use the
+        # path to the integration test dir
+        # tempfile will be used to get the proper
+        # temp dir for the OS
+        env_path = os.getenv("PATH")
+        tmp_path = tempfile.gettempdir()
+        tmp_floresta = os.path.join(tmp_path, "floresta-integration-tests")
+
+        if env_path is not None and tmp_floresta in env_path:
+            ssl_rel_path = os.path.join(
+                self.get_integration_test_dir(), "..", "..", "ssl"
             )
+            ssl_path = os.path.normpath(os.path.abspath(ssl_rel_path))
         else:
-            home = os.path.expanduser("~")  # Fixed: '~user' -> '~' for current user
             ssl_path = os.path.normpath(
-                os.path.abspath(os.path.join(home, ".floresta", "ssl"))
+                os.path.abspath(os.path.join(tmp_floresta, "ssl"))
path: tests/test_framework/test_framework.py
user: login: jaoleal
body: This is still trying to find things in other place than `$FLORESTA_TEMP_DIR` right ?
created_at: 2025-04-08T19:08:20Z
author_association: MEMBER
diff_hunk: @@ -147,17 +206,22 @@ def create_ssl_keys(self) -> tuple[str, str]:
         These keys are intended to be used with florestad's --ssl-key-path and --ssl-cert-path
         options.
         """
-        # Check if we're in CI or not
-        if "/tmp/floresta-integration-tests" in os.getenv("PATH"):
-            ssl_path = os.path.normpath(
-                os.path.abspath(
-                    os.path.join(self.get_integration_test_dir(), "..", "..", "ssl")
-                )
+        # If we're in CI, we need to use the
+        # path to the integration test dir
+        # tempfile will be used to get the proper
+        # temp dir for the OS
+        env_path = os.getenv("PATH")
+        tmp_path = tempfile.gettempdir()
+        tmp_floresta = os.path.join(tmp_path, "floresta-integration-tests")
+
+        if env_path is not None and tmp_floresta in env_path:
+            ssl_rel_path = os.path.join(
+                self.get_integration_test_dir(), "..", "..", "ssl"
             )
+            ssl_path = os.path.normpath(os.path.abspath(ssl_rel_path))
         else:
-            home = os.path.expanduser("~")  # Fixed: '~user' -> '~' for current user
             ssl_path = os.path.normpath(
-                os.path.abspath(os.path.join(home, ".floresta", "ssl"))
+                os.path.abspath(os.path.join(tmp_floresta, "ssl"))
path: tests/test_framework/test_framework.py
user: login: qlrd
body: Thanks, will change that too

created_at: 2025-04-08T19:28:08Z
author_association: CONTRIBUTOR
diff_hunk: @@ -147,17 +206,22 @@ def create_ssl_keys(self) -> tuple[str, str]:
         These keys are intended to be used with florestad's --ssl-key-path and --ssl-cert-path
         options.
         """
-        # Check if we're in CI or not
-        if "/tmp/floresta-integration-tests" in os.getenv("PATH"):
-            ssl_path = os.path.normpath(
-                os.path.abspath(
-                    os.path.join(self.get_integration_test_dir(), "..", "..", "ssl")
-                )
+        # If we're in CI, we need to use the
+        # path to the integration test dir
+        # tempfile will be used to get the proper
+        # temp dir for the OS
+        env_path = os.getenv("PATH")
+        tmp_path = tempfile.gettempdir()
+        tmp_floresta = os.path.join(tmp_path, "floresta-integration-tests")
+
+        if env_path is not None and tmp_floresta in env_path:
+            ssl_rel_path = os.path.join(
+                self.get_integration_test_dir(), "..", "..", "ssl"
             )
+            ssl_path = os.path.normpath(os.path.abspath(ssl_rel_path))
         else:
-            home = os.path.expanduser("~")  # Fixed: '~user' -> '~' for current user
             ssl_path = os.path.normpath(
-                os.path.abspath(os.path.join(home, ".floresta", "ssl"))
+                os.path.abspath(os.path.join(tmp_floresta, "ssl"))
path: tests/test_framework/test_framework.py
user: login: qlrd
body: fixed
created_at: 2025-04-09T11:45:33Z
author_association: CONTRIBUTOR
diff_hunk: @@ -76,15 +76,73 @@ def __new__(mcs, clsname, bases, dct):
         return super().__new__(mcs, clsname, bases, dct)
 
 
+# pylint: disable=too-many-public-methods
 class FlorestaTestFramework(metaclass=FlorestaTestMetaClass):
     """
-    Base class for a floresta test script.
+    Base class for a floresta test script. Individual floresta
+    test scripts should:
+
+    - subclass FlorestaTestFramework;
+    - not override the __init__() method;
+    - not override the main() method;
+    - implement set_test_params();
+    - implement run_test();
+
+    The `set_test_params` method is called before the test starts
+    and aims to configure nodes, florestad params, what should be
+    considered as expected result, and what you think should be defined.
+    It is a good practice to set the number of nodes and their
+    configuration in this method wiht `self.add_node_settings`.
path: tests/test_framework/test_framework.py
user: login: Davidson-Souza
body: typo: `wiht`
created_at: 2025-04-10T16:39:47Z
author_association: MEMBER
diff_hunk: @@ -76,15 +76,73 @@ def __new__(mcs, clsname, bases, dct):
         return super().__new__(mcs, clsname, bases, dct)
 
 
+# pylint: disable=too-many-public-methods
 class FlorestaTestFramework(metaclass=FlorestaTestMetaClass):
     """
-    Base class for a floresta test script.
+    Base class for a floresta test script. Individual floresta
+    test scripts should:
+
+    - subclass FlorestaTestFramework;
+    - not override the __init__() method;
+    - not override the main() method;
+    - implement set_test_params();
+    - implement run_test();
+
+    The `set_test_params` method is called before the test starts
+    and aims to configure nodes, florestad params, what should be
+    considered as expected result, and what you think should be defined.
+    It is a good practice to set the number of nodes and their
+    configuration in this method wiht `self.add_node_settings`.
path: tests/test_framework/test_framework.py
user: login: qlrd
body: fixed

created_at: 2025-04-11T10:36:56Z
author_association: CONTRIBUTOR

PR comments:
user: login: qlrd
created_at: 2025-04-03T12:53:45Z
body: @jaoleal, can you review [`1912458`](https://github.com/vinteumorg/Floresta/pull/434/commits/19124580de5c49c70db4b1eddf617f4c77843c31)?
author_association: CONTRIBUTOR
user: login: qlrd
created_at: 2025-04-09T13:42:16Z
body: > c`ACK`, could you squash the commits ?

Sure, i was talking right now with @Davidson-Souza about. He requested, however, to keep the commits of each suite separate.

author_association: CONTRIBUTOR
user: login: jaoleal
created_at: 2025-04-09T15:07:11Z
body: ACK a3e64e3
author_association: MEMBER