Skip to content
This repository was archived by the owner on Jun 3, 2024. It is now read-only.

Commit e7dd243

Browse files
byronbyronz
authored andcommitted
🚚 restructure and add large data
1 parent a91e118 commit e7dd243

File tree

5 files changed

+180
-508
lines changed

5 files changed

+180
-508
lines changed

tests/integration/store/conftest.py

Lines changed: 23 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,8 @@
1+
import sys
12
import json
23
import pytest
34
import uuid
5+
import mimesis
46
import dash
57
from dash.dependencies import Input, Output, State
68
from dash.exceptions import PreventUpdate
@@ -62,3 +64,24 @@ def on_click(n_clicks):
6264
return ({"n_clicks": n_clicks},) * 3
6365

6466
yield app
67+
68+
69+
@pytest.fixture(scope="module")
70+
def fake_data():
71+
buf = ""
72+
chunk = ""
73+
limit = 5 * 1024 * 1024
74+
while sys.getsizeof(buf) <= limit:
75+
g = mimesis.Generic()
76+
chunk = "\n".join(
77+
(
78+
"{},{}".format(g.person.full_name(), g.person.email())
79+
for _ in range(10000)
80+
)
81+
)
82+
buf += chunk
83+
84+
with open("/tmp/x.csv", "w") as fp:
85+
fp.write(buf[len(chunk):limit])
86+
87+
yield buf[len(chunk):limit]

tests/integration/store/test_clear_data.py

Lines changed: 0 additions & 16 deletions
This file was deleted.
Lines changed: 69 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,69 @@
1+
import json
2+
import time
3+
from pytest import approx
4+
import dash
5+
from dash.dependencies import Input, Output, State
6+
from dash.exceptions import PreventUpdate
7+
import dash_core_components as dcc
8+
import dash_html_components as html
9+
10+
11+
def test_stcp100_clear_data_on_all_types(store_app, dash_duo):
12+
dash_duo.start_server(store_app)
13+
14+
assert dash_duo.wait_for_contains_text("#output", store_app.uuid)
15+
16+
dash_duo.multiple_click("#btn", 3)
17+
assert dash_duo.get_local_storage() == {"n_clicks": 3}
18+
19+
# button click sets clear_data=True on all type of stores
20+
dash_duo.find_element("#clear-btn").click()
21+
22+
assert (
23+
not dash_duo.find_element("#output").text
24+
and not dash_duo.get_local_storage()
25+
and not dash_duo.get_session_storage()
26+
), "set clear_data=True should clear all data in three storage types"
27+
28+
29+
def test_stcp200_modified_ts(store_app, dash_duo):
30+
app = dash.Dash(__name__)
31+
app.layout = html.Div(
32+
[
33+
dcc.Store(id="initial-storage", storage_type="session"),
34+
html.Button("set-init-storage", id="set-init-storage"),
35+
html.Div(id="init-output"),
36+
]
37+
)
38+
39+
@app.callback(
40+
Output("initial-storage", "data"),
41+
[Input("set-init-storage", "n_clicks")],
42+
)
43+
def on_init(n_clicks):
44+
if n_clicks is None:
45+
raise PreventUpdate
46+
return "initialized"
47+
48+
@app.callback(
49+
Output("init-output", "children"),
50+
[Input("initial-storage", "modified_timestamp")],
51+
[State("initial-storage", "data")],
52+
)
53+
def init_output(ts, data):
54+
return json.dumps({"data": data, "ts": ts})
55+
56+
dash_duo.start_server(app)
57+
58+
dash_duo.find_element("#set-init-storage").click()
59+
# the python ts ends at seconds while javascript one ends at ms
60+
ts = float(time.time() * 1000)
61+
62+
output_data = json.loads(dash_duo.find_element("#init-output").text)
63+
64+
assert (
65+
output_data.get("data") == "initialized"
66+
), "the data should be the text set in on_init"
67+
assert ts == approx(
68+
output_data.get("ts"), abs=10
69+
), "the modified_timestamp should be updated right after the click action"
Lines changed: 87 additions & 122 deletions
Original file line numberDiff line numberDiff line change
@@ -1,110 +1,68 @@
11
import json
2-
import time
2+
import hashlib
33
import itertools
4-
from pytest import approx
54
import dash
65
from dash.dependencies import Input, Output, State
76
from dash.exceptions import PreventUpdate
87
import dash_core_components as dcc
98
import dash_html_components as html
109

1110

12-
def test_stco001_storage_component_smoke(store_app, dash_duo):
13-
11+
def test_stda001_data_types(dash_duo):
1412
app = dash.Dash(__name__)
13+
14+
types = [
15+
("str", "hello"),
16+
("number", 1),
17+
("dict", {"data": [2, 3, None]}),
18+
("list", [5, -6, 700000, 1e-12]),
19+
("null", None),
20+
("bool", True),
21+
("bool", False),
22+
("empty-dict", {}),
23+
]
24+
data_types = list(
25+
itertools.chain(*itertools.combinations(types, 2))
26+
) + [ # No combinations as it add much test time.
27+
("list-dict-1", [1, 2, {"data": [55, 66, 77], "dummy": "dum"}]),
28+
("list-dict-2", [1, 2, {"data": [111, 99, 88]}]),
29+
("dict-3", {"a": 1, "c": 1}),
30+
("dict-2", {"a": 1, "b": None}),
31+
]
32+
1533
app.layout = html.Div(
1634
[
17-
dcc.Store(id="memory", storage_type="memory"),
18-
dcc.Store(id="storage", storage_type="local"),
19-
dcc.Store(id="session", storage_type="session", data=dummy_data),
20-
dcc.Store(id="initial-storage", storage_type="session"),
21-
html.Button("click me", id="btn"),
22-
html.Button("clear", id="clear-btn"),
23-
html.Button("set-init-storage", id="set-init-storage"),
24-
html.Div(id="memory-output"),
25-
html.Div(id="init-output"),
35+
html.Div(id="output"),
36+
html.Button("click", id="click"),
37+
dcc.Store(id="store"),
2638
]
2739
)
2840

2941
@app.callback(
30-
Output("storage", "data"),
31-
[Input("btn", "n_clicks")],
32-
[State("storage", "data")],
33-
)
34-
def on_click(n_clicks, storage):
35-
if n_clicks is None:
36-
return
37-
storage = storage or {}
38-
return {"clicked": storage.get("clicked", 0) + 1}
39-
40-
@app.callback(
41-
Output("storage", "clear_data"), [Input("clear-btn", "n_clicks")]
42-
)
43-
def on_clear(n_clicks):
44-
if n_clicks is None:
45-
return
46-
return True
47-
48-
@app.callback(Output("memory", "data"), [Input("storage", "data")])
49-
def on_memory(data):
50-
return data
51-
52-
@app.callback(
53-
Output("memory-output", "children"), [Input("memory", "data")]
42+
Output("output", "children"),
43+
[Input("store", "modified_timestamp")],
44+
[State("store", "data")],
5445
)
55-
def on_memory_json(data):
56-
if data is None:
57-
return ""
46+
def on_data(ts, data):
47+
if ts is None:
48+
raise PreventUpdate
5849
return json.dumps(data)
5950

60-
@app.callback(
61-
Output("initial-storage", "data"),
62-
[Input("set-init-storage", "n_clicks")],
63-
)
64-
def on_init(n_clicks):
51+
@app.callback(Output("store", "data"), [Input("click", "n_clicks")])
52+
def on_click(n_clicks):
6553
if n_clicks is None:
6654
raise PreventUpdate
67-
68-
return "initialized"
69-
70-
@app.callback(
71-
Output("init-output", "children"),
72-
[Input("initial-storage", "modified_timestamp")],
73-
[State("initial-storage", "data")],
74-
)
75-
def init_output(ts, data):
76-
return json.dumps({"data": data, "ts": ts})
55+
return data_types[n_clicks - 1][1]
7756

7857
dash_duo.start_server(app)
7958

80-
getter = 'return JSON.parse(window.{}.getItem("{}"));'
81-
clicked_getter = getter.format("localStorage", "storage")
82-
83-
session = dash_duo.driver.execute_script(
84-
getter.format("sessionStorage", "session")
85-
)
86-
assert dummy_data == session
87-
88-
for i in range(1, 11):
89-
dash_duo.find_element("#btn").click()
90-
click_data = dash_duo.driver.execute_script(clicked_getter)
91-
assert i == click_data.get("clicked")
92-
mem = dash_duo.wait_for_element("#memory-output")
93-
assert i == int(json.loads(mem.text).get("clicked"))
94-
95-
96-
# Test initial timestamp output
97-
dash_duo.find_element("#set-init-storage").click()
98-
# the python ts ends at seconds while javascript one ends at ms
99-
ts = float(time.time() * 1000)
100-
dash_duo.driver.refresh()
101-
init = json.loads(dash_duo.wait_for_element("#init-output").text)
102-
103-
assert ts == approx(init.get("ts"), abs=10)
104-
assert init.get("data") == "initialized"
59+
button = dash_duo.wait_for_element("#click")
60+
for data_type in data_types:
61+
button.click()
62+
dash_duo.wait_for_text_to_equal("#output", json.dumps(data_type[1]))
10563

10664

107-
def test_store_nested_data(dash_duo):
65+
def test_stda002_nested_data(dash_duo):
10866
app = dash.Dash(__name__)
10967

11068
nested = {"nested": {"nest": "much"}}
@@ -148,68 +106,75 @@ def on_ts(ts, data):
148106

149107
dash_duo.start_server(app)
150108

151-
obj_btn = dash_duo.wait_for_element_by_css_selector("#obj-btn")
152-
list_btn = dash_duo.wait_for_element_by_css_selector("#list-btn")
109+
obj_btn = dash_duo.wait_for_element("#obj-btn")
110+
list_btn = dash_duo.find_element("#list-btn")
153111

154112
obj_btn.click()
155-
time.sleep(1)
156113
dash_duo.wait_for_text_to_equal("#output", json.dumps(nested))
157114
# it would of crashed the app before adding the recursive check.
158115

159116
list_btn.click()
160-
time.sleep(1)
161117
dash_duo.wait_for_text_to_equal("#output", json.dumps(nested_list))
162118

163119

164-
def test_stco003_data_type_updates(dash_duo):
165-
app = dash.Dash(__name__)
166-
167-
types = [
168-
("str", "hello"),
169-
("number", 1),
170-
("dict", {"data": [2, 3, None]}),
171-
("list", [5, -6, 700000, 1e-12]),
172-
("null", None),
173-
("bool", True),
174-
("bool", False),
175-
("empty-dict", {}),
176-
]
177-
types_changes = list(
178-
itertools.chain(*itertools.combinations(types, 2))
179-
) + [ # No combinations as it add much test time.
180-
("list-dict-1", [1, 2, {"data": [55, 66, 77], "dummy": "dum"}]),
181-
("list-dict-2", [1, 2, {"data": [111, 99, 88]}]),
182-
("dict-3", {"a": 1, "c": 1}),
183-
("dict-2", {"a": 1, "b": None}),
184-
]
120+
def test_stda003_data_size_limit(fake_data, dash_duo):
121+
def fingerprint(data):
122+
return hashlib.sha1(data.encode("utf-8")).hexdigest()
185123

124+
app = dash.Dash(__name__)
186125
app.layout = html.Div(
187126
[
188-
html.Div(id="output"),
189-
html.Button("click", id="click"),
190-
dcc.Store(id="store"),
127+
dcc.Store(id="memory", storage_type="memory"),
128+
dcc.Store(id="local", storage_type="local"),
129+
dcc.Store(id="session", storage_type="session"),
130+
html.Button("big data", id="btn"),
131+
html.Div(id="mout"),
132+
html.Div(id="sout"),
133+
html.Div(id="lout"),
191134
]
192135
)
193136

194137
@app.callback(
195-
Output("output", "children"),
196-
[Input("store", "modified_timestamp")],
197-
[State("store", "data")],
138+
[
139+
Output("mout", "children"),
140+
Output("sout", "children"),
141+
Output("lout", "children"),
142+
],
143+
[
144+
Input("memory", "modified_timestamp"),
145+
Input("session", "modified_timestamp"),
146+
Input("local", "modified_timestamp"),
147+
],
148+
[
149+
State("memory", "data"),
150+
State("session", "data"),
151+
State("local", "data"),
152+
],
198153
)
199-
def on_data(ts, data):
200-
if ts is None:
201-
raise PreventUpdate
202-
return json.dumps(data)
154+
def update_output(mts, sts, lts, mdata, sdata, ldata):
155+
if None in {mdata, sdata, ldata}:
156+
return ("nil",) * 3
157+
return [fingerprint(data) for data in (mdata, sdata, ldata)]
203158

204-
@app.callback(Output("store", "data"), [Input("click", "n_clicks")])
159+
@app.callback(
160+
[
161+
Output("memory", "data"),
162+
Output("local", "data"),
163+
Output("session", "data"),
164+
],
165+
[Input("btn", "n_clicks")],
166+
)
205167
def on_click(n_clicks):
206168
if n_clicks is None:
207169
raise PreventUpdate
208-
return types_changes[n_clicks - 1][1]
170+
return (fake_data,) * 3
209171

210172
dash_duo.start_server(app)
173+
outputs = ('#mout', '#lout', '#sout')
174+
for output in outputs:
175+
assert dash_duo.find_element(output).text == 'nil'
176+
177+
dash_duo.find_element('#btn').click()
178+
for output in outputs:
179+
dash_duo.wait_for_text_to_equal(output, fingerprint(fake_data))
211180

212-
button = dash_duo.wait_for_element("#click")
213-
for type_change in types_changes:
214-
button.click()
215-
dash_duo.wait_for_text_to_equal("#output", json.dumps(type_change[1]))

0 commit comments

Comments
 (0)