Skip to content

Commit 764e7a8

Browse files
authored
Merge pull request #177 from kbase/develop
Release v1.3.5
2 parents 795ea92 + 1752716 commit 764e7a8

File tree

4 files changed

+91
-5
lines changed

4 files changed

+91
-5
lines changed

RELEASE_NOTES.md

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,6 @@
1+
### Version 1.3.5
2+
- Fixed a bug that under some circumstances could cause incomplete file metadata to be returned.
3+
14
### Version 1.3.4
25
- Alter the behavior of the bulk specification file writers to return an error if the
36
input `types` parameter is empty.

staging_service/app.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -34,7 +34,7 @@
3434

3535
logging.basicConfig(stream=sys.stdout, level=logging.DEBUG)
3636
routes = web.RouteTableDef()
37-
VERSION = "1.3.4"
37+
VERSION = "1.3.5"
3838

3939
_DATATYPE_MAPPINGS = None
4040

staging_service/metadata.py

Lines changed: 7 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -48,7 +48,8 @@ async def _generate_metadata(path: Path, source: str):
4848
else:
4949
data = {}
5050
# first ouptut of md5sum is the checksum
51-
data["source"] = source
51+
if source:
52+
data["source"] = source
5253
try:
5354
md5 = hashlib.md5(open(path.full_path, "rb").read()).hexdigest()
5455
except:
@@ -165,7 +166,7 @@ async def some_metadata(path: Path, desired_fields=False, source=None):
165166
os.stat(path.metadata_path).st_mtime < file_stats["mtime"] / 1000
166167
):
167168
# if metadata does not exist or older than file: regenerate
168-
if source is None:
169+
if source is None: # TODO BUGFIX this will overwrite any source in the file
169170
source = _determine_source(path)
170171
data = await _generate_metadata(path, source)
171172
else: # metadata already exists and is up to date
@@ -174,9 +175,11 @@ async def some_metadata(path: Path, desired_fields=False, source=None):
174175
data = await f.read()
175176
data = decoder.decode(data)
176177
# due to legacy code, some file has corrupted metadata file
178+
# Also if a file is listed or checked for existence before the upload completes
179+
# this code block will be triggered
177180
expected_keys = ["source", "md5", "lineCount", "head", "tail"]
178-
if set(expected_keys) > set(data.keys()):
179-
if source is None:
181+
if not set(expected_keys) <= set(data.keys()):
182+
if source is None and "source" not in data:
180183
source = _determine_source(path)
181184
data = await _generate_metadata(path, source)
182185
data = {**data, **file_stats}

tests/test_metadata.py

Lines changed: 80 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,80 @@
1+
""" Unit tests for the metadata handling routines. """
2+
3+
import json
4+
import uuid
5+
6+
from collections.abc import Generator
7+
from pathlib import Path as PyPath
8+
from pytest import fixture
9+
10+
from staging_service.utils import Path
11+
from staging_service.metadata import some_metadata
12+
13+
from tests.test_app import FileUtil
14+
15+
# TODO TEST add more unit tests here.
16+
17+
18+
@fixture(scope="module")
19+
def temp_dir() -> Generator[PyPath, None, None]:
20+
with FileUtil() as fu:
21+
childdir = PyPath(fu.make_dir(str(uuid.uuid4()))).resolve()
22+
23+
yield childdir
24+
25+
# FileUtil will auto delete after exiting
26+
27+
28+
async def test_incomplete_metadata_file_update(temp_dir: Path):
29+
"""
30+
Tests the case where a file is listed or checked for existance prior to completing
31+
upload, and then an UPA is added to the file. This previously caused incomplete metadata
32+
to be returned as the logic for whether to run the metadata regeneration code based on
33+
the contents of the current metadata file was incorrect.
34+
See https://kbase-jira.atlassian.net/browse/PTV-1767
35+
"""
36+
await _incomplete_metadata_file_update(
37+
temp_dir,
38+
{"source": "some place", "UPA": "1/2/3"},
39+
"some place"
40+
)
41+
42+
await _incomplete_metadata_file_update(
43+
temp_dir,
44+
{"UPA": "1/2/3"},
45+
"Unknown"
46+
)
47+
48+
async def _incomplete_metadata_file_update(temp_dir, metadict, source):
49+
target = Path(
50+
str(temp_dir / "full"),
51+
str(temp_dir / "meta"),
52+
"user_path",
53+
"myfilename",
54+
"super_fake_jgi_path")
55+
56+
with open(target.full_path, "w") as p:
57+
p.writelines(make_test_lines(1, 6))
58+
with open(target.metadata_path, "w") as p:
59+
p.write(json.dumps(metadict))
60+
61+
res = await some_metadata(target)
62+
63+
assert "mtime" in res # just check the file time is there
64+
del res["mtime"]
65+
66+
assert res == {
67+
"source": source,
68+
"md5": "9f07da9655223b777121141ff7735f25",
69+
"head": "".join(make_test_lines(1, 5)),
70+
"tail": "".join(make_test_lines(2, 6)),
71+
"UPA": "1/2/3",
72+
"isFolder": False,
73+
"lineCount": "5",
74+
"name": "myfilename",
75+
"path": "user_path",
76+
"size": 1280
77+
}
78+
79+
def make_test_lines(start, stop):
80+
return [str(i) + "a" * (256 - len(str(i)) - 1) + "\n" for i in range(start, stop)]

0 commit comments

Comments
 (0)