Skip to content

Commit cb9f6cd

Browse files
authored
Merge pull request #357 from IoT-Inspector/basic-metadata
Basic metadata
2 parents d85aba8 + 5a7ada4 commit cb9f6cd

21 files changed

+1113
-310
lines changed

.github/workflows/build-publish-image.yml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -52,7 +52,7 @@ jobs:
5252
run: docker run --rm ${{ env.DOCKER_IMAGE }} --show-external-dependencies
5353

5454
- name: Check unblob - run for a file with --verbose
55-
run: docker run --rm -v "$(pwd)"/tests/integration/archive/zip/regular:/test ${{ env.DOCKER_IMAGE }} -v -e /tmp /test
55+
run: docker run --rm -v "$(pwd)"/tests/integration/archive/zip/regular:/test ${{ env.DOCKER_IMAGE }} -v -e /tmp /test/__input__/apple.zip
5656

5757
- name: Build and push
5858
if: ${{ github.event_name == 'push' && github.ref_name == 'main' }}

.github/workflows/main.yml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -66,4 +66,4 @@ jobs:
6666
uses: ./.github/actions/setup-git-lfs
6767

6868
- name: Run pytest
69-
run: poetry run pytest
69+
run: poetry run pytest -vvv

default.nix

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -111,7 +111,7 @@ self // {
111111
112112
# romfs sample file contains some funky symlinks which get
113113
# removed when source is copyed to the nix store.
114-
pytest -k "not test_all_handlers[filesystem.romfs]" --no-cov
114+
pytest -vvv -k "not test_all_handlers[filesystem.romfs]" --no-cov
115115
)
116116
'';
117117
});

tests/conftest.py

Lines changed: 9 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -1,15 +1,15 @@
1-
from unblob.extractors import Command
2-
from unblob.models import Handler, HexString
1+
from pathlib import Path
2+
3+
import pytest
4+
5+
from unblob.models import Task, TaskResult
36
from unblob.testing import ( # noqa: F401 (module imported but unused)
47
configure_logging,
58
extraction_config,
69
)
710

811

9-
class TestHandler(Handler):
10-
NAME = "test_handler"
11-
PATTERNS = [HexString("21 3C")]
12-
EXTRACTOR = Command("testcommand", "for", "test", "handler")
13-
14-
def calculate_chunk(self, *args, **kwargs):
15-
pass
12+
@pytest.fixture
13+
def task_result():
14+
task = Task(path=Path("/nonexistent"), depth=0, chunk_id="")
15+
return TaskResult(task)

tests/extractors/test_command.py

Lines changed: 0 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -51,7 +51,6 @@ def test_command_execution_failure(tmpdir: Path):
5151
except ExtractError as e:
5252
assert list(e.reports) == [
5353
ExtractCommandFailedReport(
54-
handler=None,
5554
command=mock.ANY,
5655
stdout=b"stdout",
5756
stderr=b"stderr",
@@ -70,7 +69,6 @@ def test_command_not_found(tmpdir: Path):
7069
except ExtractError as e:
7170
assert list(e.reports) == [
7271
ExtractorDependencyNotFoundReport(
73-
handler=None,
7472
dependencies=["this-command-should-not-exist-in-any-system"],
7573
)
7674
]

tests/test_cleanup.py

Lines changed: 20 additions & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -9,7 +9,8 @@
99
import pytest
1010

1111
from unblob.models import File, Handler, Regex, ValidChunk
12-
from unblob.processing import ExtractionConfig, process_files
12+
from unblob.processing import ExtractionConfig, process_file
13+
from unblob.testing import check_result
1314

1415
_ZIP_CONTENT = b"good file"
1516
# replacing _ZIP_CONTENT with _DAMAGED_ZIP_CONTENT will result in CRC error at unpacking time
@@ -33,10 +34,8 @@ def wrapzip(filename: str, content: bytes) -> bytes:
3334

3435

3536
@pytest.fixture()
36-
def input_dir(tmp_path: Path):
37-
input_dir = tmp_path / "input"
38-
input_dir.mkdir()
39-
return input_dir
37+
def input_file(tmp_path: Path):
38+
return tmp_path / "input_file"
4039

4140

4241
@pytest.fixture()
@@ -46,41 +45,41 @@ def output_dir(tmp_path):
4645
return output_dir
4746

4847

49-
def test_remove_extracted_chunks(input_dir: Path, output_dir: Path):
50-
(input_dir / "blob").write_bytes(ZIP_BYTES)
48+
def test_remove_extracted_chunks(input_file: Path, output_dir: Path):
49+
input_file.write_bytes(ZIP_BYTES)
5150
config = ExtractionConfig(
5251
extract_root=output_dir,
5352
entropy_depth=0,
5453
)
5554

56-
all_reports = process_files(config, input_dir)
55+
all_reports = process_file(config, input_file)
5756
assert list(output_dir.glob("**/*.zip")) == []
58-
assert all_reports == [], f"Unexpected error reports: {all_reports}"
57+
check_result(all_reports)
5958

6059

61-
def test_keep_all_problematic_chunks(input_dir: Path, output_dir: Path):
62-
(input_dir / "blob").write_bytes(DAMAGED_ZIP_BYTES)
60+
def test_keep_all_problematic_chunks(input_file: Path, output_dir: Path):
61+
input_file.write_bytes(DAMAGED_ZIP_BYTES)
6362
config = ExtractionConfig(
6463
extract_root=output_dir,
6564
entropy_depth=0,
6665
)
6766

68-
all_reports = process_files(config, input_dir)
67+
all_reports = process_file(config, input_file)
6968
# damaged zip file should not be removed
70-
assert all_reports != [], "Unexpectedly no errors found!"
69+
assert all_reports.errors != [], "Unexpectedly no errors found!"
7170
assert list(output_dir.glob("**/*.zip"))
7271

7372

74-
def test_keep_all_unknown_chunks(input_dir: Path, output_dir: Path):
75-
(input_dir / "blob").write_bytes(b"unknown1" + ZIP_BYTES + b"unknown2")
73+
def test_keep_all_unknown_chunks(input_file: Path, output_dir: Path):
74+
input_file.write_bytes(b"unknown1" + ZIP_BYTES + b"unknown2")
7675
config = ExtractionConfig(
7776
extract_root=output_dir,
7877
entropy_depth=0,
7978
)
8079

81-
all_reports = process_files(config, input_dir)
80+
all_reports = process_file(config, input_file)
8281
assert list(output_dir.glob("**/*.unknown"))
83-
assert all_reports == [], f"Unexpected error reports: {all_reports}"
82+
check_result(all_reports)
8483

8584

8685
class _HandlerWithNullExtractor(Handler):
@@ -92,13 +91,13 @@ def calculate_chunk(self, file: File, start_offset: int) -> ValidChunk:
9291
return ValidChunk(start_offset=start_offset, end_offset=start_offset + 1)
9392

9493

95-
def test_keep_chunks_with_null_extractor(input_dir: Path, output_dir: Path):
96-
(input_dir / "blob").write_text("some text")
94+
def test_keep_chunks_with_null_extractor(input_file: Path, output_dir: Path):
95+
input_file.write_bytes(b"some text")
9796
config = ExtractionConfig(
9897
extract_root=output_dir,
9998
entropy_depth=0,
10099
handlers=(_HandlerWithNullExtractor,),
101100
)
102-
all_reports = process_files(config, input_dir)
101+
all_reports = process_file(config, input_file)
103102
assert list(output_dir.glob("**/*.null"))
104-
assert all_reports == [], f"Unexpected error reports: {all_reports}"
103+
check_result(all_reports)

tests/test_cli.py

Lines changed: 27 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -4,14 +4,23 @@
44

55
import pytest
66
from click.testing import CliRunner
7-
from conftest import TestHandler
87

98
import unblob.cli
109
from unblob.extractors import Command
1110
from unblob.handlers import BUILTIN_HANDLERS
11+
from unblob.models import Handler, HexString
1212
from unblob.processing import DEFAULT_DEPTH, DEFAULT_PROCESS_NUM, ExtractionConfig
1313

1414

15+
class TestHandler(Handler):
16+
NAME = "test_handler"
17+
PATTERNS = [HexString("21 3C")]
18+
EXTRACTOR = Command("testcommand", "for", "test", "handler")
19+
20+
def calculate_chunk(self, *args, **kwargs):
21+
pass
22+
23+
1524
class ExistingCommandHandler(TestHandler):
1625
EXTRACTOR = Command("sh", "something")
1726

@@ -86,7 +95,7 @@ def test_help(params):
8695
result = runner.invoke(unblob.cli.cli, params)
8796
assert result.exit_code == 0
8897
# NOTE: In practice, it writes "Usage: unblob ...", this is done in the `cli.main` with `click.make_context`
89-
assert result.output.startswith("Usage: cli [OPTIONS] FILES...")
98+
assert result.output.startswith("Usage: cli [OPTIONS] FILE")
9099

91100

92101
@pytest.mark.parametrize(
@@ -118,19 +127,19 @@ def test_without_file(params: List[str]):
118127
runner = CliRunner()
119128
result = runner.invoke(unblob.cli.cli, params)
120129
assert result.exit_code == 2
121-
assert "Missing argument 'FILES...'" in result.output
130+
assert "Missing argument 'FILE'" in result.output
122131

123132

124133
def test_non_existing_file(tmp_path: Path):
125134
runner = CliRunner()
126135
path = Path("non/existing/path/54")
127136
result = runner.invoke(unblob.cli.cli, ["--extract-dir", str(tmp_path), str(path)])
128137
assert result.exit_code == 2
129-
assert "Invalid value for 'FILES...'" in result.output
130-
assert f"Path '{str(path)}' does not exist" in result.output
138+
assert "Invalid value for 'FILE'" in result.output
139+
assert f"File '{str(path)}' does not exist" in result.output
131140

132141

133-
def test_empty_dir_as_file(tmp_path: Path):
142+
def test_dir_for_file(tmp_path: Path):
134143
runner = CliRunner()
135144
out_path = tmp_path.joinpath("out")
136145
out_path.mkdir()
@@ -139,7 +148,7 @@ def test_empty_dir_as_file(tmp_path: Path):
139148
result = runner.invoke(
140149
unblob.cli.cli, ["--extract-dir", str(out_path), str(in_path)]
141150
)
142-
assert result.exit_code == 0
151+
assert result.exit_code != 0
143152

144153

145154
@pytest.mark.parametrize(
@@ -172,13 +181,14 @@ def test_archive_success(
172181
/ "archive"
173182
/ "zip"
174183
/ "regular"
175-
/ "__input__/"
184+
/ "__input__"
185+
/ "apple.zip"
176186
)
177-
process_files_mock = mock.MagicMock()
187+
process_file_mock = mock.MagicMock()
178188
logger_config_mock = mock.MagicMock()
179189
new_params = params + ["--extract-dir", str(tmp_path), str(in_path)]
180190
with mock.patch.object(
181-
unblob.cli, "process_files", process_files_mock
191+
unblob.cli, "process_file", process_file_mock
182192
), mock.patch.object(unblob.cli, "configure_logger", logger_config_mock):
183193
result = runner.invoke(unblob.cli.cli, new_params)
184194
assert result.exit_code == 0
@@ -192,7 +202,7 @@ def test_archive_success(
192202
process_num=expected_process_num,
193203
handlers=BUILTIN_HANDLERS,
194204
)
195-
process_files_mock.assert_called_once_with(config, in_path)
205+
process_file_mock.assert_called_once_with(config, in_path, None)
196206
logger_config_mock.assert_called_once_with(expected_verbosity, tmp_path)
197207

198208

@@ -214,17 +224,18 @@ def test_keep_extracted_chunks(
214224
/ "archive"
215225
/ "zip"
216226
/ "regular"
217-
/ "__input__/"
227+
/ "__input__"
228+
/ "apple.zip"
218229
)
219230
params = args + ["--extract-dir", str(tmp_path), str(in_path)]
220231

221-
process_files_mock = mock.MagicMock()
222-
with mock.patch.object(unblob.cli, "process_files", process_files_mock):
232+
process_file_mock = mock.MagicMock()
233+
with mock.patch.object(unblob.cli, "process_file", process_file_mock):
223234
result = runner.invoke(unblob.cli.cli, params)
224235

225236
assert result.exit_code == 0
226-
process_files_mock.assert_called_once()
237+
process_file_mock.assert_called_once()
227238
assert (
228-
process_files_mock.call_args.args[0].keep_extracted_chunks
239+
process_file_mock.call_args.args[0].keep_extracted_chunks
229240
== keep_extracted_chunks
230241
), fail_message

0 commit comments

Comments
 (0)