please the coverage gods

This commit is contained in:
Maximilian Hils 2021-08-20 14:32:12 +02:00
parent 8561a620c8
commit 2945ba925b
8 changed files with 256 additions and 82 deletions

View File

@ -137,7 +137,8 @@ class Dumper:
human.format_address(flow.client_conn.peername) human.format_address(flow.client_conn.peername)
) )
) )
else: else: # pragma: no cover
# this should not happen, but we're defensive here.
client = "" client = ""
pushed = ' PUSH_PROMISE' if 'h2-pushed-stream' in flow.metadata else '' pushed = ' PUSH_PROMISE' if 'h2-pushed-stream' in flow.metadata else ''

View File

@ -224,22 +224,26 @@ async def test_load(tmpdir):
def test_resolve(): def test_resolve():
v = view.View() v = view.View()
with taddons.context() as tctx: with taddons.context() as tctx:
f = tft(method="get")
assert tctx.command(v.resolve, "@all") == [] assert tctx.command(v.resolve, "@all") == []
assert tctx.command(v.resolve, "@focus") == [] assert tctx.command(v.resolve, "@focus") == []
assert tctx.command(v.resolve, "@shown") == [] assert tctx.command(v.resolve, "@shown") == []
assert tctx.command(v.resolve, "@hidden") == [] assert tctx.command(v.resolve, "@hidden") == []
assert tctx.command(v.resolve, "@marked") == [] assert tctx.command(v.resolve, "@marked") == []
assert tctx.command(v.resolve, "@unmarked") == [] assert tctx.command(v.resolve, "@unmarked") == []
assert tctx.command(v.resolve, f"@{f.id}") == []
assert tctx.command(v.resolve, "~m get") == [] assert tctx.command(v.resolve, "~m get") == []
v.request(tft(method="get")) v.request(f)
assert len(tctx.command(v.resolve, "~m get")) == 1 assert len(tctx.command(v.resolve, "~m get")) == 1
assert len(tctx.command(v.resolve, "@focus")) == 1 assert len(tctx.command(v.resolve, "@focus")) == 1
assert len(tctx.command(v.resolve, "@all")) == 1 assert len(tctx.command(v.resolve, "@all")) == 1
assert len(tctx.command(v.resolve, "@shown")) == 1 assert len(tctx.command(v.resolve, "@shown")) == 1
assert len(tctx.command(v.resolve, "@unmarked")) == 1 assert len(tctx.command(v.resolve, "@unmarked")) == 1
assert len(tctx.command(v.resolve, f"@{f.id}")) == 1
assert tctx.command(v.resolve, "@hidden") == [] assert tctx.command(v.resolve, "@hidden") == []
assert tctx.command(v.resolve, "@marked") == [] assert tctx.command(v.resolve, "@marked") == []
v.request(tft(method="put")) v.request(tft(method="put"))
assert len(tctx.command(v.resolve, f"@{f.id}")) == 1
assert len(tctx.command(v.resolve, "@focus")) == 1 assert len(tctx.command(v.resolve, "@focus")) == 1
assert len(tctx.command(v.resolve, "@shown")) == 2 assert len(tctx.command(v.resolve, "@shown")) == 2
assert len(tctx.command(v.resolve, "@all")) == 2 assert len(tctx.command(v.resolve, "@all")) == 2
@ -624,4 +628,4 @@ def test_configure():
[":not valid:", SYMBOL_MARK], [":weird", SYMBOL_MARK] [":not valid:", SYMBOL_MARK], [":weird", SYMBOL_MARK]
]) ])
def test_marker(marker, expected): def test_marker(marker, expected):
assert render_marker(marker) == expected assert render_marker(marker) == expected

View File

@ -18,7 +18,7 @@ import tornado.testing
from tornado import httpclient from tornado import httpclient
from tornado import websocket from tornado import websocket
from mitmproxy import options, optmanager from mitmproxy import certs, options, optmanager
from mitmproxy.test import tflow from mitmproxy.test import tflow
from mitmproxy.tools.web import app from mitmproxy.tools.web import app
from mitmproxy.tools.web import master as webmaster from mitmproxy.tools.web import master as webmaster
@ -39,7 +39,81 @@ def get_json(resp: httpclient.HTTPResponse):
return _json.loads(resp.body.decode()) return _json.loads(resp.body.decode())
@pytest.mark.usefixtures("no_tornado_logging") def test_generate_tflow_js(tdata):
tf = tflow.tflow(resp=True, err=True, ws=True)
tf.server_conn.certificate_list = [
certs.Cert.from_pem(
Path(tdata.path("mitmproxy/net/data/verificationcerts/self-signed.pem")).read_bytes()
)
]
tf.request.trailers = Headers(trailer="qvalue")
tf.response.trailers = Headers(trailer="qvalue")
_tflow = app.flow_to_json(tf)
# Set some value as constant, so that _tflow.js would not change every time.
_tflow['id'] = "d91165be-ca1f-4612-88a9-c0f8696f3e29"
_tflow['client_conn']['id'] = "4a18d1a0-50a1-48dd-9aa6-d45d74282939"
_tflow['server_conn']['id'] = "f087e7b2-6d0a-41a8-a8f0-e1a4761395f8"
tflow_json = _json.dumps(_tflow, indent=4, sort_keys=True)
tflow_json = re.sub(
r'( {8}"(address|is_replay|alpn_proto_negotiated)":)',
r" //@ts-ignore\n\1",
tflow_json
).replace(": null", ": undefined")
content = (
"/** Auto-generated by test_app.py:test_generate_tflow_js */\n"
"import {HTTPFlow} from '../../flow';\n"
"export default function(): Required<HTTPFlow> {\n"
f" return {tflow_json}\n"
"}"
)
(Path(__file__).parent / "../../../../web/src/js/__tests__/ducks/_tflow.ts").write_bytes(
content.encode()
)
def test_generate_options_js():
o = options.Options()
m = webmaster.WebMaster(o)
opt: optmanager._Option
def ts_type(t):
if t == bool:
return "boolean"
if t == str:
return "string"
if t == int:
return "number"
if t == typing.Sequence[str]:
return "string[]"
if t == typing.Optional[str]:
return "string | undefined"
raise RuntimeError(t)
with redirect_stdout(io.StringIO()) as s:
print("/** Auto-generated by test_app.py:test_generate_options_js */")
print("export interface OptionsState {")
for _, opt in sorted(m.options.items()):
print(f" {opt.name}: {ts_type(opt.typespec)}")
print("}")
print("")
print("export type Option = keyof OptionsState")
print("")
print("export const defaultState: OptionsState = {")
for _, opt in sorted(m.options.items()):
print(f" {opt.name}: {json.dumps(opt.default)},".replace(": null", ": undefined"))
print("}")
(Path(__file__).parent / "../../../../web/src/js/ducks/_options_gen.ts").write_bytes(
s.getvalue().encode()
)
@pytest.mark.usefixtures("no_tornado_logging", "tdata")
class TestApp(tornado.testing.AsyncHTTPTestCase): class TestApp(tornado.testing.AsyncHTTPTestCase):
def get_new_ioloop(self): def get_new_ioloop(self):
io_loop = tornado.platform.asyncio.AsyncIOLoop() io_loop = tornado.platform.asyncio.AsyncIOLoop()
@ -51,6 +125,7 @@ class TestApp(tornado.testing.AsyncHTTPTestCase):
m = webmaster.WebMaster(o, with_termlog=False) m = webmaster.WebMaster(o, with_termlog=False)
f = tflow.tflow(resp=True) f = tflow.tflow(resp=True)
f.id = "42" f.id = "42"
f.request.content = b"foo\nbar"
m.view.add([f]) m.view.add([f])
m.view.add([tflow.tflow(err=True)]) m.view.add([tflow.tflow(err=True)])
m.log.info("test log") m.log.info("test log")
@ -153,7 +228,8 @@ class TestApp(tornado.testing.AsyncHTTPTestCase):
"code": 404, "code": 404,
"headers": [("bar", "baz")], "headers": [("bar", "baz")],
"content": "resp", "content": "resp",
} },
"marked": ":red_circle:",
} }
assert self.put_json("/flows/42", upd).code == 200 assert self.put_json("/flows/42", upd).code == 200
assert f.request.method == "PATCH" assert f.request.method == "PATCH"
@ -252,10 +328,17 @@ class TestApp(tornado.testing.AsyncHTTPTestCase):
assert f.modified() assert f.modified()
f.revert() f.revert()
def test_flow_content_view(self): def test_flow_contentview(self):
assert get_json(self.fetch("/flows/42/request/content/raw")) == { assert get_json(self.fetch("/flows/42/request/content/raw")) == {
"lines": [ "lines": [
[["text", "content"]] [["text", "foo"]],
[["text", "bar"]]
],
"description": "Raw"
}
assert get_json(self.fetch("/flows/42/request/content/raw?lines=1")) == {
"lines": [
[["text", "foo"]]
], ],
"description": "Raw" "description": "Raw"
} }
@ -322,70 +405,3 @@ class TestApp(tornado.testing.AsyncHTTPTestCase):
# trigger on_close by opening a second connection. # trigger on_close by opening a second connection.
ws_client2 = yield websocket.websocket_connect(ws_url) ws_client2 = yield websocket.websocket_connect(ws_url)
ws_client2.close() ws_client2.close()
def test_generate_tflow_js(self):
tf = tflow.tflow(resp=True, err=True, ws=True)
tf.request.trailers = Headers(trailer="qvalue")
tf.response.trailers = Headers(trailer="qvalue")
_tflow = app.flow_to_json(tf)
# Set some value as constant, so that _tflow.js would not change every time.
_tflow['id'] = "d91165be-ca1f-4612-88a9-c0f8696f3e29"
_tflow['client_conn']['id'] = "4a18d1a0-50a1-48dd-9aa6-d45d74282939"
_tflow['server_conn']['id'] = "f087e7b2-6d0a-41a8-a8f0-e1a4761395f8"
tflow_json = _json.dumps(_tflow, indent=4, sort_keys=True)
tflow_json = re.sub(
r'( {8}"(address|is_replay|alpn_proto_negotiated)":)',
r" //@ts-ignore\n\1",
tflow_json
).replace(": null", ": undefined")
content = (
"/** Auto-generated by test_app.py:TestApp.test_generate_tflow_js */\n"
"import {HTTPFlow} from '../../flow';\n"
"export default function(): Required<HTTPFlow> {\n"
f" return {tflow_json}\n"
"}"
)
(Path(__file__).parent / "../../../../web/src/js/__tests__/ducks/_tflow.ts").write_bytes(
content.encode()
)
def test_generate_options_js(self):
o = options.Options()
m = webmaster.WebMaster(o)
opt: optmanager._Option
def ts_type(t):
if t == bool:
return "boolean"
if t == str:
return "string"
if t == int:
return "number"
if t == typing.Sequence[str]:
return "string[]"
if t == typing.Optional[str]:
return "string | undefined"
raise RuntimeError(t)
with redirect_stdout(io.StringIO()) as s:
print("/** Auto-generated by test_app.py:TestApp.test_generate_options_js */")
print("export interface OptionsState {")
for _, opt in sorted(m.options.items()):
print(f" {opt.name}: {ts_type(opt.typespec)}")
print("}")
print("")
print("export type Option = keyof OptionsState")
print("")
print("export const defaultState: OptionsState = {")
for _, opt in sorted(m.options.items()):
print(f" {opt.name}: {json.dumps(opt.default)},".replace(": null", ": undefined"))
print("}")
(Path(__file__).parent / "../../../../web/src/js/ducks/_options_gen.ts").write_bytes(
s.getvalue().encode()
)

View File

@ -13,7 +13,8 @@ module.exports = async () => {
], ],
"coverageDirectory": "./coverage", "coverageDirectory": "./coverage",
"coveragePathIgnorePatterns": [ "coveragePathIgnorePatterns": [
"<rootDir>/src/js/filt/filt.js" "<rootDir>/src/js/filt/filt.js",
"<rootDir>/src/js/filt/command.js"
], ],
"collectCoverageFrom": [ "collectCoverageFrom": [
"src/js/**/*.{js,jsx,ts,tsx}" "src/js/**/*.{js,jsx,ts,tsx}"

View File

@ -1,9 +1,6 @@
{ {
"name": "mitmproxy", "name": "mitmproxy",
"private": true, "private": true,
"jest": {
"verbose": true
},
"scripts": { "scripts": {
"test": "tsc --noEmit && jest --coverage", "test": "tsc --noEmit && jest --coverage",
"build": "gulp prod", "build": "gulp prod",

View File

@ -611,6 +611,121 @@ exports[`FlowView 4`] = `
</tr> </tr>
</tbody> </tbody>
</table> </table>
<h4>
Server Certificate
</h4>
<table
class="certificate-table"
>
<tbody>
<tr>
<td>
Type
</td>
<td>
RSA, 2048 bits
</td>
</tr>
<tr>
<td>
SHA256 digest
</td>
<td>
e5f62a1175031b6feb959bc8e6dd0f8e2546dbbf7c32da39534309d8aa92967c
</td>
</tr>
<tr>
<td>
Valid from
</td>
<td>
2020-11-03 06:03:27
</td>
</tr>
<tr>
<td>
Valid to
</td>
<td>
2040-10-29 06:03:27
</td>
</tr>
<tr>
<td>
Subject Alternative Names
</td>
<td>
example.mitmproxy.org
</td>
</tr>
<tr>
<td>
Subject
</td>
<td>
<dl
class="cert-attributes"
>
<dt>
C
</dt>
<dd>
AU
</dd>
<dt>
ST
</dt>
<dd>
Some-State
</dd>
<dt>
O
</dt>
<dd>
Internet Widgits Pty Ltd
</dd>
</dl>
</td>
</tr>
<tr>
<td>
Issuer
</td>
<td>
<dl
class="cert-attributes"
>
<dt>
C
</dt>
<dd>
AU
</dd>
<dt>
ST
</dt>
<dd>
Some-State
</dd>
<dt>
O
</dt>
<dd>
Internet Widgits Pty Ltd
</dd>
</dl>
</td>
</tr>
<tr>
<td>
Serial
</td>
<td>
247170098335718583458667965517443538258472437317
</td>
</tr>
</tbody>
</table>
</section> </section>
</div> </div>
</DocumentFragment> </DocumentFragment>

View File

@ -1,4 +1,4 @@
/** Auto-generated by test_app.py:TestApp.test_generate_tflow_js */ /** Auto-generated by test_app.py:test_generate_tflow_js */
import {HTTPFlow} from '../../flow'; import {HTTPFlow} from '../../flow';
export default function(): Required<HTTPFlow> { export default function(): Required<HTTPFlow> {
return { return {
@ -90,7 +90,47 @@ export default function(): Required<HTTPFlow> {
22 22
], ],
"alpn": undefined, "alpn": undefined,
"cert": undefined, "cert": {
"altnames": [
"example.mitmproxy.org"
],
"issuer": [
[
"C",
"AU"
],
[
"ST",
"Some-State"
],
[
"O",
"Internet Widgits Pty Ltd"
]
],
"keyinfo": [
"RSA",
2048
],
"notafter": 2235103407,
"notbefore": 1604383407,
"serial": "247170098335718583458667965517443538258472437317",
"sha256": "e5f62a1175031b6feb959bc8e6dd0f8e2546dbbf7c32da39534309d8aa92967c",
"subject": [
[
"C",
"AU"
],
[
"ST",
"Some-State"
],
[
"O",
"Internet Widgits Pty Ltd"
]
]
},
"cipher": undefined, "cipher": undefined,
"id": "f087e7b2-6d0a-41a8-a8f0-e1a4761395f8", "id": "f087e7b2-6d0a-41a8-a8f0-e1a4761395f8",
"peername": [ "peername": [

View File

@ -1,4 +1,4 @@
/** Auto-generated by test_app.py:TestApp.test_generate_options_js */ /** Auto-generated by test_app.py:test_generate_options_js */
export interface OptionsState { export interface OptionsState {
add_upstream_certs_to_client_chain: boolean add_upstream_certs_to_client_chain: boolean
allow_hosts: string[] allow_hosts: string[]