mirror of
https://github.com/sqlmapproject/sqlmap.git
synced 2026-07-06 08:22:57 +00:00
Some more stabilization of unittests
This commit is contained in:
parent
71d9c6d0f4
commit
d60e95ede7
20 changed files with 122 additions and 33 deletions
|
|
@ -86,6 +86,7 @@ class _ApiServerCase(unittest.TestCase):
|
|||
"""
|
||||
|
||||
def setUp(self):
|
||||
self._saved_batch = conf.batch
|
||||
conf.batch = True
|
||||
|
||||
# snapshot mutated globals
|
||||
|
|
@ -122,6 +123,7 @@ class _ApiServerCase(unittest.TestCase):
|
|||
api.DataStore.username = self._saved["username"]
|
||||
api.DataStore.password = self._saved["password"]
|
||||
api.Database.filepath = self._saved["filepath"]
|
||||
conf.batch = self._saved_batch
|
||||
|
||||
def _new_task(self):
|
||||
code, parsed, _ = _wsgi_call("GET", "/task/new")
|
||||
|
|
|
|||
|
|
@ -28,14 +28,26 @@ from lib.core.bigarray import BigArray
|
|||
N = 5000
|
||||
|
||||
|
||||
_SPILLED = []
|
||||
|
||||
def _make_spilled():
|
||||
# tiny chunk_size guarantees many on-disk chunks for N items
|
||||
ba = BigArray(chunk_size=1024)
|
||||
for i in range(N):
|
||||
ba.append("item-%d" % i)
|
||||
_SPILLED.append(ba) # tracked so tearDownModule closes it (release the on-disk chunk files)
|
||||
return ba
|
||||
|
||||
|
||||
def tearDownModule():
|
||||
for ba in _SPILLED:
|
||||
try:
|
||||
ba.close()
|
||||
except Exception:
|
||||
pass
|
||||
del _SPILLED[:]
|
||||
|
||||
|
||||
class TestSpill(unittest.TestCase):
|
||||
def test_actually_spilled_to_disk(self):
|
||||
ba = _make_spilled()
|
||||
|
|
|
|||
|
|
@ -53,9 +53,10 @@ _CONF_KEYS = (
|
|||
"notString", "regexp", "regex", "dummy", "offline", "skipWaf", "data",
|
||||
"hashDB", "cj", "cookie", "dropSetCookie", "httpHeaders", "proxy", "tor",
|
||||
"tamper", "timeout", "retries", "textOnly", "ignoreCode", "disablePrecon",
|
||||
"ipv6", "multipleTargets", "level", "base64Parameter", "batch",
|
||||
"ipv6", "multipleTargets", "level", "base64Parameter", "batch", "code", "titles",
|
||||
)
|
||||
_KB_KEYS = (
|
||||
"pageTemplate", "negativeLogic",
|
||||
"heavilyDynamic", "dynamicParameter", "originalPage", "originalPageTime",
|
||||
"originalCode", "ignoreCasted", "heuristicMode", "disableHtmlDecoding",
|
||||
"heuristicTest", "heuristicPage", "heuristicCode", "pageStable",
|
||||
|
|
|
|||
|
|
@ -1320,10 +1320,9 @@ class TestCommonChunkSplit(unittest.TestCase):
|
|||
random.choice, random.randint, random.sample, random.seed = _saved
|
||||
|
||||
def test_chunk_split_terminator(self):
|
||||
import random
|
||||
from lib.core.common import chunkSplitPostData
|
||||
random.seed(123)
|
||||
# regardless of content, the chunked stream must end with the zero-length terminator
|
||||
# (assertion is seed-independent, so don't touch the global RNG)
|
||||
self.assertTrue(chunkSplitPostData("abc").endswith("0\r\n\r\n"))
|
||||
|
||||
|
||||
|
|
|
|||
|
|
@ -25,6 +25,7 @@ logic fails the test. No live target / network / DBMS involved.
|
|||
|
||||
import os
|
||||
import sys
|
||||
import tempfile
|
||||
import unittest
|
||||
|
||||
sys.path.insert(0, os.path.dirname(os.path.abspath(__file__)))
|
||||
|
|
@ -108,7 +109,7 @@ class TestGenericFilesystem(_FsBase):
|
|||
def test_fileEncode_reads_then_encodes(self):
|
||||
# fileEncode must read the file bytes and delegate to fileContentEncode
|
||||
path = os.path.join(
|
||||
os.environ.get("TMPDIR", "/tmp"), "sqlmap_fe_%d.bin" % os.getpid())
|
||||
tempfile.gettempdir(), "sqlmap_fe_%d.bin" % os.getpid())
|
||||
with open(path, "wb") as f:
|
||||
f.write(b"hello")
|
||||
try:
|
||||
|
|
@ -138,7 +139,7 @@ class TestGenericFilesystem(_FsBase):
|
|||
# MySQL builds LENGTH(LOAD_FILE('<remote>')) and compares to local size.
|
||||
set_dbms("MySQL")
|
||||
path = os.path.join(
|
||||
os.environ.get("TMPDIR", "/tmp"), "sqlmap_cl_%d.bin" % os.getpid())
|
||||
tempfile.gettempdir(), "sqlmap_cl_%d.bin" % os.getpid())
|
||||
with open(path, "wb") as f:
|
||||
f.write(b"12345") # 5 bytes
|
||||
captured = {}
|
||||
|
|
@ -159,7 +160,7 @@ class TestGenericFilesystem(_FsBase):
|
|||
def test_checkFileLength_size_differs(self):
|
||||
set_dbms("MySQL")
|
||||
path = os.path.join(
|
||||
os.environ.get("TMPDIR", "/tmp"), "sqlmap_cl2_%d.bin" % os.getpid())
|
||||
tempfile.gettempdir(), "sqlmap_cl2_%d.bin" % os.getpid())
|
||||
with open(path, "wb") as f:
|
||||
f.write(b"12345") # local 5
|
||||
self.patch(self.module.inject, "getValue", lambda q, *a, **k: "9")
|
||||
|
|
@ -176,7 +177,7 @@ class TestGenericFilesystem(_FsBase):
|
|||
# OPENROWSET-building branch runs in isolation.
|
||||
set_dbms("Microsoft SQL Server")
|
||||
path = os.path.join(
|
||||
os.environ.get("TMPDIR", "/tmp"), "sqlmap_cl3_%d.bin" % os.getpid())
|
||||
tempfile.gettempdir(), "sqlmap_cl3_%d.bin" % os.getpid())
|
||||
with open(path, "wb") as f:
|
||||
f.write(b"ABCD") # 4 bytes
|
||||
stacked = []
|
||||
|
|
@ -205,7 +206,7 @@ class TestGenericFilesystem(_FsBase):
|
|||
# non-positive remote size -> treated as "not written" -> sameFile False
|
||||
set_dbms("MySQL")
|
||||
path = os.path.join(
|
||||
os.environ.get("TMPDIR", "/tmp"), "sqlmap_cl4_%d.bin" % os.getpid())
|
||||
tempfile.gettempdir(), "sqlmap_cl4_%d.bin" % os.getpid())
|
||||
with open(path, "wb") as f:
|
||||
f.write(b"x")
|
||||
self.patch(self.module.inject, "getValue", lambda q, *a, **k: None)
|
||||
|
|
@ -282,7 +283,7 @@ class TestGenericFilesystem(_FsBase):
|
|||
# stackedWriteFile and return its result.
|
||||
set_dbms("MySQL")
|
||||
path = os.path.join(
|
||||
os.environ.get("TMPDIR", "/tmp"), "sqlmap_wf_%d.bin" % os.getpid())
|
||||
tempfile.gettempdir(), "sqlmap_wf_%d.bin" % os.getpid())
|
||||
with open(path, "wb") as f:
|
||||
f.write(b"data")
|
||||
calls = {}
|
||||
|
|
|
|||
|
|
@ -16,6 +16,21 @@ bootstrap()
|
|||
|
||||
import lib.techniques.ldap.inject as ldap
|
||||
|
||||
# several setUps here write these conf keys without restoring them; snapshot/restore at the module
|
||||
# boundary so they can't leak into later test modules (order-dependent flakiness)
|
||||
_LDAP_CONF_KEYS = ("parameters", "paramDict", "skipUrlEncode", "cookieDel")
|
||||
_saved_conf = {}
|
||||
|
||||
def setUpModule():
|
||||
from lib.core.data import conf
|
||||
for k in _LDAP_CONF_KEYS:
|
||||
_saved_conf[k] = conf.get(k)
|
||||
|
||||
def tearDownModule():
|
||||
from lib.core.data import conf
|
||||
for k, v in _saved_conf.items():
|
||||
conf[k] = v
|
||||
|
||||
# --- Helpers ----------------------------------------------------------------
|
||||
|
||||
SENTINEL = ldap.SENTINEL
|
||||
|
|
|
|||
|
|
@ -18,6 +18,21 @@ bootstrap()
|
|||
|
||||
import lib.techniques.nosql.inject as ni
|
||||
|
||||
# several setUps here write these conf keys without restoring them; snapshot/restore at the module
|
||||
# boundary so they can't leak into later test modules (order-dependent flakiness)
|
||||
_NOSQL_CONF_KEYS = ("parameters", "paramDict", "timeSec", "cookieDel")
|
||||
_saved_conf = {}
|
||||
|
||||
def setUpModule():
|
||||
from lib.core.data import conf
|
||||
for k in _NOSQL_CONF_KEYS:
|
||||
_saved_conf[k] = conf.get(k)
|
||||
|
||||
def tearDownModule():
|
||||
from lib.core.data import conf
|
||||
for k, v in _saved_conf.items():
|
||||
conf[k] = v
|
||||
|
||||
SECRET = "S3cr3t_9"
|
||||
MATCH = "<html><body>Welcome user; rows: alpha, bravo, charlie</body></html>"
|
||||
NOMATCH = "<html><body>Invalid credentials; no rows</body></html>"
|
||||
|
|
|
|||
|
|
@ -60,6 +60,7 @@ class TestExtractTextTagContent(unittest.TestCase):
|
|||
|
||||
class TestParseSqliteTableSchema(unittest.TestCase):
|
||||
def setUp(self):
|
||||
self.addCleanup(setattr, kb.data, "cachedColumns", kb.data.get("cachedColumns"))
|
||||
kb.data.cachedColumns = {}
|
||||
|
||||
def _cols(self):
|
||||
|
|
|
|||
|
|
@ -28,6 +28,24 @@ from lib.core.settings import (JSON_RECOGNITION_REGEX, JSON_LIKE_RECOGNITION_REG
|
|||
# change there is reflected here too.
|
||||
MARK = CUSTOM_INJECTION_MARK_CHAR
|
||||
|
||||
# the _drive_* helpers set sticky conf/kb flags (notably conf.hpp, which changes queryPage
|
||||
# behaviour) without restoring them; snapshot/restore at the module boundary so they can't leak
|
||||
_PM_CONF_KEYS = ("hpp", "skipUrlEncode", "method", "paramDel", "url", "data", "parameters", "paramDict")
|
||||
_PM_KB_KEYS = ("tamperFunctions", "postHint", "customInjectionMark", "postUrlEncode", "postSpaceToPlus", "processUserMarks")
|
||||
_pm_saved = {}
|
||||
|
||||
def setUpModule():
|
||||
from lib.core.data import conf, kb
|
||||
for k in _PM_CONF_KEYS:
|
||||
_pm_saved[("conf", k)] = conf.get(k)
|
||||
for k in _PM_KB_KEYS:
|
||||
_pm_saved[("kb", k)] = kb.get(k)
|
||||
|
||||
def tearDownModule():
|
||||
from lib.core.data import conf, kb
|
||||
for (scope, k), v in _pm_saved.items():
|
||||
(conf if scope == "conf" else kb)[k] = v
|
||||
|
||||
|
||||
def classify(d):
|
||||
if re.search(JSON_RECOGNITION_REGEX, d):
|
||||
|
|
|
|||
|
|
@ -83,7 +83,10 @@ class TestPurge(unittest.TestCase):
|
|||
nonempty = [p for p in survivors if os.path.getsize(p) > 0]
|
||||
self.assertEqual(nonempty, [], msg="files were not truncated to zero: %r" % nonempty)
|
||||
|
||||
blob = b"".join(open(p, "rb").read() for p in survivors)
|
||||
blob = b""
|
||||
for p in survivors:
|
||||
with open(p, "rb") as fh:
|
||||
blob += fh.read()
|
||||
for secret in plaintexts.values():
|
||||
self.assertNotIn(secret.encode("utf-8"), blob,
|
||||
msg="original plaintext %r survived the purge" % secret)
|
||||
|
|
|
|||
|
|
@ -191,6 +191,7 @@ class TestEntityConversion(unittest.TestCase):
|
|||
class TestCustomEntitydefs(unittest.TestCase):
|
||||
def test_custom_entity(self):
|
||||
p = RecordingParser()
|
||||
p.entitydefs = dict(p.entitydefs) # shadow the shared SGMLParser class dict so 'copy' doesn't leak process-wide
|
||||
p.entitydefs["copy"] = "\xa9"
|
||||
p.feed("©")
|
||||
p.close()
|
||||
|
|
|
|||
|
|
@ -393,8 +393,7 @@ class TestExecuteCommand(unittest.TestCase):
|
|||
|
||||
def tearDown(self):
|
||||
ssti._send = self.original_send
|
||||
if self.original_dumper is not None:
|
||||
ssti.conf.dumper = self.original_dumper
|
||||
ssti.conf.dumper = self.original_dumper # restore unconditionally (was None -> don't leak the mock dumper)
|
||||
|
||||
def test_error_page_skipped(self):
|
||||
"""RCE payload that triggers a template error is skipped; next payload tried."""
|
||||
|
|
|
|||
|
|
@ -26,6 +26,20 @@ bootstrap()
|
|||
from lib.core.common import parseTargetUrl
|
||||
from lib.core.data import conf
|
||||
|
||||
_TARGETURL_KEYS = ("url", "hostname", "port", "scheme", "path")
|
||||
_saved = {}
|
||||
|
||||
|
||||
def setUpModule():
|
||||
for k in _TARGETURL_KEYS:
|
||||
_saved[k] = conf.get(k)
|
||||
|
||||
|
||||
def tearDownModule():
|
||||
# parseTargetUrl() writes these onto the global conf singleton; restore so it can't leak to later modules
|
||||
for k, v in _saved.items():
|
||||
conf[k] = v
|
||||
|
||||
|
||||
def _parse(url):
|
||||
conf.url = url
|
||||
|
|
|
|||
|
|
@ -46,6 +46,7 @@ class TestFilterStringValue(unittest.TestCase):
|
|||
|
||||
class TestParseFilePaths(unittest.TestCase):
|
||||
def setUp(self):
|
||||
self.addCleanup(setattr, kb, "absFilePaths", kb.get("absFilePaths"))
|
||||
kb.absFilePaths = set()
|
||||
|
||||
def test_unix_paths_from_php_error(self):
|
||||
|
|
|
|||
|
|
@ -38,6 +38,7 @@ class TestThreadData(unittest.TestCase):
|
|||
# ATTRIBUTE STATE is per-thread. Verify both: same object, independent state.
|
||||
main = T.getCurrentThreadData()
|
||||
self.assertIs(main, T.getCurrentThreadData()) # stable within a thread
|
||||
self.addCleanup(main.reset) # don't leak the main thread's mutated state to later tests
|
||||
|
||||
main.retriesCount = 111
|
||||
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue