arthexis 0.1.8__py3-none-any.whl → 0.1.10__py3-none-any.whl
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Potentially problematic release.
This version of arthexis might be problematic. Click here for more details.
- {arthexis-0.1.8.dist-info → arthexis-0.1.10.dist-info}/METADATA +87 -6
- arthexis-0.1.10.dist-info/RECORD +95 -0
- arthexis-0.1.10.dist-info/licenses/LICENSE +674 -0
- config/__init__.py +0 -1
- config/auth_app.py +0 -1
- config/celery.py +1 -2
- config/context_processors.py +1 -1
- config/offline.py +2 -0
- config/settings.py +352 -37
- config/urls.py +71 -6
- core/admin.py +1601 -200
- core/admin_history.py +50 -0
- core/admindocs.py +108 -1
- core/apps.py +161 -3
- core/auto_upgrade.py +57 -0
- core/backends.py +123 -7
- core/entity.py +62 -48
- core/fields.py +98 -0
- core/github_helper.py +25 -0
- core/github_issues.py +172 -0
- core/lcd_screen.py +1 -0
- core/liveupdate.py +25 -0
- core/log_paths.py +100 -0
- core/mailer.py +83 -0
- core/middleware.py +57 -0
- core/models.py +1279 -267
- core/notifications.py +11 -1
- core/public_wifi.py +227 -0
- core/reference_utils.py +97 -0
- core/release.py +27 -20
- core/sigil_builder.py +144 -0
- core/sigil_context.py +20 -0
- core/sigil_resolver.py +284 -0
- core/system.py +162 -29
- core/tasks.py +269 -27
- core/test_system_info.py +59 -1
- core/tests.py +644 -73
- core/tests_liveupdate.py +17 -0
- core/urls.py +2 -2
- core/user_data.py +425 -168
- core/views.py +627 -59
- core/widgets.py +51 -0
- core/workgroup_urls.py +7 -3
- core/workgroup_views.py +43 -6
- nodes/actions.py +0 -2
- nodes/admin.py +168 -285
- nodes/apps.py +9 -15
- nodes/backends.py +145 -0
- nodes/lcd.py +24 -10
- nodes/models.py +579 -179
- nodes/tasks.py +1 -5
- nodes/tests.py +894 -130
- nodes/utils.py +13 -2
- nodes/views.py +204 -28
- ocpp/admin.py +212 -63
- ocpp/apps.py +1 -1
- ocpp/consumers.py +642 -68
- ocpp/evcs.py +30 -10
- ocpp/models.py +452 -70
- ocpp/simulator.py +75 -11
- ocpp/store.py +288 -30
- ocpp/tasks.py +11 -7
- ocpp/test_export_import.py +8 -7
- ocpp/test_rfid.py +211 -16
- ocpp/tests.py +1576 -137
- ocpp/transactions_io.py +68 -22
- ocpp/urls.py +35 -2
- ocpp/views.py +701 -123
- pages/admin.py +173 -13
- pages/checks.py +0 -1
- pages/context_processors.py +39 -6
- pages/forms.py +131 -0
- pages/middleware.py +153 -0
- pages/models.py +37 -9
- pages/tests.py +1182 -42
- pages/urls.py +4 -0
- pages/utils.py +0 -1
- pages/views.py +844 -51
- arthexis-0.1.8.dist-info/RECORD +0 -80
- arthexis-0.1.8.dist-info/licenses/LICENSE +0 -21
- config/workgroup_app.py +0 -7
- core/checks.py +0 -29
- {arthexis-0.1.8.dist-info → arthexis-0.1.10.dist-info}/WHEEL +0 -0
- {arthexis-0.1.8.dist-info → arthexis-0.1.10.dist-info}/top_level.txt +0 -0
ocpp/test_rfid.py
CHANGED
|
@@ -1,9 +1,16 @@
|
|
|
1
|
+
import io
|
|
1
2
|
import os
|
|
3
|
+
import sys
|
|
4
|
+
import types
|
|
5
|
+
from pathlib import Path
|
|
2
6
|
from unittest.mock import patch, MagicMock, call
|
|
3
7
|
|
|
8
|
+
import pytest
|
|
9
|
+
|
|
4
10
|
os.environ.setdefault("DJANGO_SETTINGS_MODULE", "config.settings")
|
|
5
11
|
|
|
6
12
|
import django
|
|
13
|
+
|
|
7
14
|
django.setup()
|
|
8
15
|
|
|
9
16
|
from django.test import SimpleTestCase, TestCase
|
|
@@ -16,9 +23,54 @@ from nodes.models import Node, NodeRole
|
|
|
16
23
|
|
|
17
24
|
from core.models import RFID
|
|
18
25
|
from ocpp.rfid.reader import read_rfid, enable_deep_read
|
|
26
|
+
from ocpp.rfid.detect import detect_scanner, main as detect_main
|
|
27
|
+
from ocpp.rfid import background_reader
|
|
28
|
+
from ocpp.rfid.constants import (
|
|
29
|
+
DEFAULT_IRQ_PIN,
|
|
30
|
+
DEFAULT_RST_PIN,
|
|
31
|
+
GPIO_PIN_MODE_BCM,
|
|
32
|
+
MODULE_WIRING,
|
|
33
|
+
SPI_BUS,
|
|
34
|
+
SPI_DEVICE,
|
|
35
|
+
)
|
|
36
|
+
|
|
19
37
|
|
|
38
|
+
pytestmark = [pytest.mark.feature("rfid-scanner")]
|
|
20
39
|
|
|
21
|
-
|
|
40
|
+
|
|
41
|
+
class BackgroundReaderConfigurationTests(SimpleTestCase):
|
|
42
|
+
def setUp(self):
|
|
43
|
+
background_reader._auto_detect_logged = False
|
|
44
|
+
|
|
45
|
+
def tearDown(self):
|
|
46
|
+
background_reader._auto_detect_logged = False
|
|
47
|
+
|
|
48
|
+
def test_is_configured_auto_detects_without_lock(self):
|
|
49
|
+
fake_lock = Path("/tmp/rfid-auto-detect.lock")
|
|
50
|
+
with (
|
|
51
|
+
patch("ocpp.rfid.background_reader._lock_path", return_value=fake_lock),
|
|
52
|
+
patch("ocpp.rfid.background_reader._has_spi_device", return_value=True),
|
|
53
|
+
patch(
|
|
54
|
+
"ocpp.rfid.background_reader._dependencies_available",
|
|
55
|
+
return_value=True,
|
|
56
|
+
),
|
|
57
|
+
):
|
|
58
|
+
self.assertTrue(background_reader.is_configured())
|
|
59
|
+
|
|
60
|
+
def test_is_configured_requires_dependencies(self):
|
|
61
|
+
fake_lock = Path("/tmp/rfid-auto-detect.lock")
|
|
62
|
+
with (
|
|
63
|
+
patch("ocpp.rfid.background_reader._lock_path", return_value=fake_lock),
|
|
64
|
+
patch("ocpp.rfid.background_reader._has_spi_device", return_value=True),
|
|
65
|
+
patch(
|
|
66
|
+
"ocpp.rfid.background_reader._dependencies_available",
|
|
67
|
+
return_value=False,
|
|
68
|
+
),
|
|
69
|
+
):
|
|
70
|
+
self.assertFalse(background_reader.is_configured())
|
|
71
|
+
|
|
72
|
+
|
|
73
|
+
class ScanNextViewTests(TestCase):
|
|
22
74
|
@patch("config.middleware.Node.get_local", return_value=None)
|
|
23
75
|
@patch("config.middleware.get_site")
|
|
24
76
|
@patch(
|
|
@@ -64,6 +116,13 @@ class ReaderNotificationTests(TestCase):
|
|
|
64
116
|
def MFRC522_Anticoll(self):
|
|
65
117
|
return (self.MI_OK, [0xAB, 0xCD, 0x12, 0x34, 0x56])
|
|
66
118
|
|
|
119
|
+
def MFRC522_SelectTag(self, _uid):
|
|
120
|
+
self.select_called = True
|
|
121
|
+
return self.MI_OK
|
|
122
|
+
|
|
123
|
+
def MFRC522_StopCrypto1(self):
|
|
124
|
+
self.stop_called = True
|
|
125
|
+
|
|
67
126
|
return MockReader()
|
|
68
127
|
|
|
69
128
|
@patch("ocpp.rfid.reader.notify_async")
|
|
@@ -80,14 +139,15 @@ class ReaderNotificationTests(TestCase):
|
|
|
80
139
|
)
|
|
81
140
|
mock_get.return_value = (tag, False)
|
|
82
141
|
|
|
83
|
-
|
|
142
|
+
reader = self._mock_reader()
|
|
143
|
+
result = read_rfid(mfrc=reader, cleanup=False)
|
|
84
144
|
self.assertEqual(result["label_id"], 1)
|
|
85
145
|
self.assertEqual(result["kind"], RFID.CLASSIC)
|
|
86
146
|
self.assertEqual(result["reference"], "https://example.com")
|
|
87
147
|
self.assertEqual(mock_notify.call_count, 1)
|
|
88
|
-
mock_notify.assert_has_calls(
|
|
89
|
-
|
|
90
|
-
)
|
|
148
|
+
mock_notify.assert_has_calls([call("RFID 1 OK", f"{result['rfid']} B")])
|
|
149
|
+
self.assertTrue(getattr(reader, "select_called", False))
|
|
150
|
+
self.assertTrue(getattr(reader, "stop_called", False))
|
|
91
151
|
|
|
92
152
|
@patch("ocpp.rfid.reader.notify_async")
|
|
93
153
|
@patch("core.models.RFID.objects.get_or_create")
|
|
@@ -102,12 +162,13 @@ class ReaderNotificationTests(TestCase):
|
|
|
102
162
|
)
|
|
103
163
|
mock_get.return_value = (tag, False)
|
|
104
164
|
|
|
105
|
-
|
|
165
|
+
reader = self._mock_reader()
|
|
166
|
+
result = read_rfid(mfrc=reader, cleanup=False)
|
|
106
167
|
self.assertEqual(result["kind"], RFID.CLASSIC)
|
|
107
168
|
self.assertEqual(mock_notify.call_count, 1)
|
|
108
|
-
mock_notify.assert_has_calls(
|
|
109
|
-
|
|
110
|
-
)
|
|
169
|
+
mock_notify.assert_has_calls([call("RFID 2 BAD", f"{result['rfid']} B")])
|
|
170
|
+
self.assertTrue(getattr(reader, "select_called", False))
|
|
171
|
+
self.assertTrue(getattr(reader, "stop_called", False))
|
|
111
172
|
|
|
112
173
|
|
|
113
174
|
class CardTypeDetectionTests(TestCase):
|
|
@@ -125,12 +186,33 @@ class CardTypeDetectionTests(TestCase):
|
|
|
125
186
|
[0x04, 0xD3, 0x2A, 0x1B, 0x5F, 0x23, 0x19],
|
|
126
187
|
)
|
|
127
188
|
|
|
189
|
+
def MFRC522_SelectTag(self, _uid):
|
|
190
|
+
self.select_called = True
|
|
191
|
+
return self.MI_OK
|
|
192
|
+
|
|
193
|
+
def MFRC522_StopCrypto1(self):
|
|
194
|
+
self.stop_called = True
|
|
195
|
+
|
|
128
196
|
return MockReader()
|
|
129
197
|
|
|
130
198
|
@patch("ocpp.rfid.reader.notify_async")
|
|
131
|
-
|
|
132
|
-
|
|
199
|
+
@patch("core.models.RFID.objects.get_or_create")
|
|
200
|
+
def test_detects_ntag215(self, mock_get, _mock_notify):
|
|
201
|
+
tag = MagicMock(
|
|
202
|
+
pk=1,
|
|
203
|
+
label_id=1,
|
|
204
|
+
allowed=True,
|
|
205
|
+
color="B",
|
|
206
|
+
released=False,
|
|
207
|
+
reference=None,
|
|
208
|
+
kind=RFID.NTAG215,
|
|
209
|
+
)
|
|
210
|
+
mock_get.return_value = (tag, True)
|
|
211
|
+
reader = self._mock_ntag_reader()
|
|
212
|
+
result = read_rfid(mfrc=reader, cleanup=False)
|
|
133
213
|
self.assertEqual(result["kind"], RFID.NTAG215)
|
|
214
|
+
self.assertTrue(getattr(reader, "select_called", False))
|
|
215
|
+
self.assertTrue(getattr(reader, "stop_called", False))
|
|
134
216
|
|
|
135
217
|
|
|
136
218
|
class RFIDLastSeenTests(TestCase):
|
|
@@ -145,15 +227,78 @@ class RFIDLastSeenTests(TestCase):
|
|
|
145
227
|
def MFRC522_Anticoll(self):
|
|
146
228
|
return (self.MI_OK, [0xAB, 0xCD, 0x12, 0x34])
|
|
147
229
|
|
|
230
|
+
def MFRC522_SelectTag(self, _uid):
|
|
231
|
+
self.select_called = True
|
|
232
|
+
return self.MI_OK
|
|
233
|
+
|
|
234
|
+
def MFRC522_StopCrypto1(self):
|
|
235
|
+
self.stop_called = True
|
|
236
|
+
|
|
148
237
|
return MockReader()
|
|
149
238
|
|
|
150
239
|
@patch("ocpp.rfid.reader.notify_async")
|
|
151
240
|
def test_last_seen_updated_on_read(self, _mock_notify):
|
|
152
241
|
tag = RFID.objects.create(rfid="ABCD1234")
|
|
153
|
-
|
|
242
|
+
reader = self._mock_reader()
|
|
243
|
+
result = read_rfid(mfrc=reader, cleanup=False)
|
|
154
244
|
tag.refresh_from_db()
|
|
155
245
|
self.assertIsNotNone(tag.last_seen_on)
|
|
156
246
|
self.assertEqual(result["kind"], RFID.CLASSIC)
|
|
247
|
+
self.assertTrue(getattr(reader, "select_called", False))
|
|
248
|
+
self.assertTrue(getattr(reader, "stop_called", False))
|
|
249
|
+
|
|
250
|
+
|
|
251
|
+
class RFIDDetectionScriptTests(SimpleTestCase):
|
|
252
|
+
@patch("ocpp.rfid.detect._ensure_django")
|
|
253
|
+
@patch(
|
|
254
|
+
"ocpp.rfid.irq_wiring_check.check_irq_pin",
|
|
255
|
+
return_value={"irq_pin": DEFAULT_IRQ_PIN},
|
|
256
|
+
)
|
|
257
|
+
def test_detect_scanner_success(self, mock_check, _mock_setup):
|
|
258
|
+
result = detect_scanner()
|
|
259
|
+
self.assertEqual(
|
|
260
|
+
result,
|
|
261
|
+
{
|
|
262
|
+
"detected": True,
|
|
263
|
+
"irq_pin": DEFAULT_IRQ_PIN,
|
|
264
|
+
},
|
|
265
|
+
)
|
|
266
|
+
mock_check.assert_called_once()
|
|
267
|
+
|
|
268
|
+
@patch("ocpp.rfid.detect._ensure_django")
|
|
269
|
+
@patch(
|
|
270
|
+
"ocpp.rfid.irq_wiring_check.check_irq_pin",
|
|
271
|
+
return_value={"error": "no scanner detected"},
|
|
272
|
+
)
|
|
273
|
+
def test_detect_scanner_failure(self, mock_check, _mock_setup):
|
|
274
|
+
result = detect_scanner()
|
|
275
|
+
self.assertFalse(result["detected"])
|
|
276
|
+
self.assertEqual(result["reason"], "no scanner detected")
|
|
277
|
+
mock_check.assert_called_once()
|
|
278
|
+
|
|
279
|
+
@patch(
|
|
280
|
+
"ocpp.rfid.detect.detect_scanner",
|
|
281
|
+
return_value={"detected": True, "irq_pin": DEFAULT_IRQ_PIN},
|
|
282
|
+
)
|
|
283
|
+
def test_detect_main_success_output(self, mock_detect):
|
|
284
|
+
buffer = io.StringIO()
|
|
285
|
+
with patch("sys.stdout", new=buffer):
|
|
286
|
+
exit_code = detect_main([])
|
|
287
|
+
self.assertEqual(exit_code, 0)
|
|
288
|
+
self.assertIn("IRQ pin", buffer.getvalue())
|
|
289
|
+
mock_detect.assert_called_once()
|
|
290
|
+
|
|
291
|
+
@patch(
|
|
292
|
+
"ocpp.rfid.detect.detect_scanner",
|
|
293
|
+
return_value={"detected": False, "reason": "missing hardware"},
|
|
294
|
+
)
|
|
295
|
+
def test_detect_main_failure_output(self, mock_detect):
|
|
296
|
+
buffer = io.StringIO()
|
|
297
|
+
with patch("sys.stdout", new=buffer):
|
|
298
|
+
exit_code = detect_main([])
|
|
299
|
+
self.assertEqual(exit_code, 1)
|
|
300
|
+
self.assertIn("missing hardware", buffer.getvalue())
|
|
301
|
+
mock_detect.assert_called_once()
|
|
157
302
|
|
|
158
303
|
|
|
159
304
|
class RestartViewTests(SimpleTestCase):
|
|
@@ -201,9 +346,8 @@ class RFIDLandingTests(TestCase):
|
|
|
201
346
|
app = Application.objects.create(name="Ocpp")
|
|
202
347
|
module = Module.objects.create(node_role=role, application=app, path="/ocpp/")
|
|
203
348
|
module.create_landings()
|
|
204
|
-
self.assertTrue(
|
|
205
|
-
|
|
206
|
-
)
|
|
349
|
+
self.assertTrue(module.landings.filter(path="/ocpp/rfid/").exists())
|
|
350
|
+
|
|
207
351
|
|
|
208
352
|
class ScannerTemplateTests(TestCase):
|
|
209
353
|
def setUp(self):
|
|
@@ -284,7 +428,10 @@ class ReaderPollingTests(SimpleTestCase):
|
|
|
284
428
|
class DeepReadViewTests(TestCase):
|
|
285
429
|
@patch("config.middleware.Node.get_local", return_value=None)
|
|
286
430
|
@patch("config.middleware.get_site")
|
|
287
|
-
@patch(
|
|
431
|
+
@patch(
|
|
432
|
+
"ocpp.rfid.views.enable_deep_read_mode",
|
|
433
|
+
return_value={"status": "deep", "timeout": 60},
|
|
434
|
+
)
|
|
288
435
|
def test_enable_deep_read(self, mock_enable, mock_site, mock_node):
|
|
289
436
|
User = get_user_model()
|
|
290
437
|
staff = User.objects.create_user("staff4", password="pwd", is_staff=True)
|
|
@@ -343,3 +490,51 @@ class DeepReadAuthTests(TestCase):
|
|
|
343
490
|
self.assertEqual(reader.auth_calls[1], reader.PICC_AUTHENT1B)
|
|
344
491
|
|
|
345
492
|
|
|
493
|
+
class RFIDWiringConfigTests(SimpleTestCase):
|
|
494
|
+
def test_module_wiring_map(self):
|
|
495
|
+
expected = [
|
|
496
|
+
("SDA", "CE0"),
|
|
497
|
+
("SCK", "SCLK"),
|
|
498
|
+
("MOSI", "MOSI"),
|
|
499
|
+
("MISO", "MISO"),
|
|
500
|
+
("IRQ", "IO4"),
|
|
501
|
+
("GND", "GND"),
|
|
502
|
+
("RST", "IO25"),
|
|
503
|
+
("3v3", "3v3"),
|
|
504
|
+
]
|
|
505
|
+
self.assertEqual(list(MODULE_WIRING.items()), expected)
|
|
506
|
+
self.assertEqual(DEFAULT_IRQ_PIN, 4)
|
|
507
|
+
self.assertEqual(DEFAULT_RST_PIN, 25)
|
|
508
|
+
|
|
509
|
+
def test_background_reader_uses_default_irq_pin(self):
|
|
510
|
+
self.assertEqual(background_reader.IRQ_PIN, DEFAULT_IRQ_PIN)
|
|
511
|
+
|
|
512
|
+
def test_reader_instantiation_uses_configured_pins(self):
|
|
513
|
+
class DummyReader:
|
|
514
|
+
init_args = None
|
|
515
|
+
init_kwargs = None
|
|
516
|
+
|
|
517
|
+
def __init__(self, *args, **kwargs):
|
|
518
|
+
DummyReader.init_args = args
|
|
519
|
+
DummyReader.init_kwargs = kwargs
|
|
520
|
+
self.MI_OK = 1
|
|
521
|
+
self.PICC_REQIDL = 0
|
|
522
|
+
|
|
523
|
+
fake_mfrc = types.ModuleType("mfrc522")
|
|
524
|
+
fake_mfrc.MFRC522 = DummyReader
|
|
525
|
+
fake_gpio = types.ModuleType("RPi.GPIO")
|
|
526
|
+
fake_rpi = types.ModuleType("RPi")
|
|
527
|
+
fake_rpi.GPIO = fake_gpio
|
|
528
|
+
|
|
529
|
+
with patch.dict(
|
|
530
|
+
"sys.modules",
|
|
531
|
+
{"mfrc522": fake_mfrc, "RPi": fake_rpi, "RPi.GPIO": fake_gpio},
|
|
532
|
+
):
|
|
533
|
+
result = read_rfid(timeout=0, cleanup=False)
|
|
534
|
+
|
|
535
|
+
self.assertEqual(result, {"rfid": None, "label_id": None})
|
|
536
|
+
self.assertIsNotNone(DummyReader.init_kwargs)
|
|
537
|
+
self.assertEqual(DummyReader.init_kwargs["bus"], SPI_BUS)
|
|
538
|
+
self.assertEqual(DummyReader.init_kwargs["device"], SPI_DEVICE)
|
|
539
|
+
self.assertEqual(DummyReader.init_kwargs["pin_mode"], GPIO_PIN_MODE_BCM)
|
|
540
|
+
self.assertEqual(DummyReader.init_kwargs["pin_rst"], DEFAULT_RST_PIN)
|