Phase 2.9 complete
This commit is contained in:
+195
-5
@@ -1277,7 +1277,7 @@ class UGCAnimationTests(UGCMediaTestCase, UGCGatedTestCase):
|
||||
self.assertIn('missionary', names)
|
||||
self.assertIn('bugged', names)
|
||||
|
||||
def test_version_upload_warns_without_animation_id(self):
|
||||
def test_animation_pack_without_id_gets_injected(self):
|
||||
self.project = Project.objects.create(
|
||||
slug='anim-pack', title='Anim Pack', category='non_pack', owner=self.alice,
|
||||
)
|
||||
@@ -1285,11 +1285,9 @@ class UGCAnimationTests(UGCMediaTestCase, UGCGatedTestCase):
|
||||
self.assertRedirects(resp, reverse('library:project_detail', args=['anim-pack']),
|
||||
fetch_redirect_response=False)
|
||||
version = self.project.versions.first()
|
||||
self.assertEqual(version.animation_id, '')
|
||||
# The missing id is auto-assigned instead of warning.
|
||||
self.assertEqual(version.animation_id, f'alice:project_{self.project.pk}')
|
||||
self.assertTrue(version.animation_manifest)
|
||||
# The warning banner renders on the redirect target (before it's consumed).
|
||||
resp = self.client.get(reverse('library:project_detail', args=['anim-pack']))
|
||||
self.assertContains(resp, 'incompatible with the update-check API')
|
||||
|
||||
def test_latest_api_returns_version_and_url(self):
|
||||
self.project = Project.objects.create(
|
||||
@@ -1574,3 +1572,195 @@ class UGCThumbnailTests(UGCMediaTestCase, UGCGatedTestCase):
|
||||
self.gate()
|
||||
resp = self.client.get(reverse('library:project_detail', args=['media']))
|
||||
self.assertContains(resp, '/thumb/')
|
||||
|
||||
|
||||
def _stored_mcmeta(version):
|
||||
from django.core.files.storage import default_storage
|
||||
release = version.files.filter(kind='release').first()
|
||||
with default_storage.open(release.file.stored_path, 'rb') as f:
|
||||
with zipfile.ZipFile(f) as zf:
|
||||
return json.loads(zf.read('pack.mcmeta').decode('utf-8'))
|
||||
|
||||
|
||||
class UGCAnimationIdTests(UGCMediaTestCase, UGCGatedTestCase):
|
||||
def setUp(self):
|
||||
User = get_user_model()
|
||||
self.alice = User.objects.create_user(username='Alice', password='pw')
|
||||
UserProfile.objects.get_or_create(user=self.alice)
|
||||
|
||||
def _write_zip(self, data):
|
||||
with tempfile.NamedTemporaryFile(suffix='.zip', delete=False) as f:
|
||||
f.write(data)
|
||||
return f.name
|
||||
|
||||
def _upload_version(self, slug, name, content):
|
||||
self.gate()
|
||||
self.client.login(username='Alice', password='pw')
|
||||
resp = self.client.post(
|
||||
reverse('library:api_upload_temp'),
|
||||
{'kind': 'version', 'file': SimpleUploadedFile(name, content, content_type='application/zip')},
|
||||
HTTP_X_REQUESTED_WITH='XMLHttpRequest',
|
||||
)
|
||||
self.assertEqual(resp.status_code, 200)
|
||||
return self.client.post(
|
||||
reverse('library:version_upload', args=[slug]),
|
||||
{'version_name': '1.0.0'},
|
||||
)
|
||||
|
||||
def test_inject_merge_and_create(self):
|
||||
from library.zips import inject_animationframework
|
||||
path = self._write_zip(_logical_zip())
|
||||
try:
|
||||
ok = inject_animationframework(path, {'id': 'alice:project_1', 'name': 'X',
|
||||
'author': 'Alice', 'version': '1.0', 'description': 'y'})
|
||||
self.assertTrue(ok)
|
||||
with zipfile.ZipFile(path) as zf:
|
||||
mc = json.loads(zf.read('pack.mcmeta').decode('utf-8'))
|
||||
self.assertEqual(mc['animationframework']['id'], 'alice:project_1')
|
||||
self.assertEqual(mc['pack']['pack_format'], 61) # existing block preserved
|
||||
|
||||
path2 = self._write_zip(_zip_bytes({'data/x.txt': 'x'}))
|
||||
inject_animationframework(path2, {'id': 'a:b'})
|
||||
with zipfile.ZipFile(path2) as zf:
|
||||
mc2 = json.loads(zf.read('pack.mcmeta').decode('utf-8'))
|
||||
self.assertEqual(mc2['pack']['pack_format'], 64)
|
||||
self.assertEqual(mc2['pack']['supported_formats'], [64, 81])
|
||||
self.assertEqual(mc2['pack']['min_format'], 64)
|
||||
self.assertEqual(mc2['pack']['max_format'], 81)
|
||||
self.assertEqual(mc2['animationframework']['id'], 'a:b')
|
||||
finally:
|
||||
os.unlink(path)
|
||||
|
||||
def test_version_upload_injects_defaults(self):
|
||||
self.project = Project.objects.create(
|
||||
slug='np', title='NoN Pack', category='non_pack', owner=self.alice,
|
||||
)
|
||||
resp = self._upload_version('np', 'pack.zip', _logical_zip())
|
||||
self.assertRedirects(resp, reverse('library:project_detail', args=['np']))
|
||||
version = self.project.versions.first()
|
||||
expected = f'alice:project_{self.project.pk}'
|
||||
self.assertEqual(version.animation_id, expected)
|
||||
mc = _stored_mcmeta(version)
|
||||
self.assertEqual(mc['animationframework']['id'], expected)
|
||||
self.assertEqual(mc['animationframework']['name'], 'NoN Pack')
|
||||
# latest API works for the injected id.
|
||||
self.gate()
|
||||
resp = self.client.get(reverse('library:api_packs_latest', args=['alice', f'project_{self.project.pk}']))
|
||||
self.assertEqual(resp.status_code, 200)
|
||||
self.assertEqual(resp.json()['version'], '1.0.0')
|
||||
# Download is not truncated: FileIndex size refreshed after injection.
|
||||
release = version.files.first()
|
||||
resp = self.client.get(reverse('library:file_request', args=[release.file.uuid]))
|
||||
served = b''.join(resp.streaming_content)
|
||||
self.assertEqual(int(resp['Content-Length']), release.file.size)
|
||||
self.assertEqual(len(served), release.file.size)
|
||||
with zipfile.ZipFile(io.BytesIO(served)) as zf:
|
||||
self.assertIsNone(zf.testzip())
|
||||
|
||||
def test_version_upload_establishes_from_pack(self):
|
||||
self.project = Project.objects.create(
|
||||
slug='np', title='NoN Pack', category='non_pack', owner=self.alice,
|
||||
)
|
||||
self._upload_version('np', 'pack.zip', _animation_pack_zip())
|
||||
version = self.project.versions.first()
|
||||
self.assertEqual(version.animation_id, 'jakebreath:testpack')
|
||||
|
||||
def test_version_upload_reuses_project_id(self):
|
||||
self.project = Project.objects.create(
|
||||
slug='np', title='NoN Pack', category='non_pack', owner=self.alice,
|
||||
)
|
||||
self._upload_version('np', 'pack.zip', _animation_pack_zip()) # establishes jakebreath:testpack
|
||||
self._upload_version('np', 'pack2.zip', _logical_zip()) # no id → reuse
|
||||
versions = list(self.project.versions.order_by('created_at'))
|
||||
self.assertEqual(versions[-1].animation_id, 'jakebreath:testpack')
|
||||
|
||||
def test_different_id_requires_confirm(self):
|
||||
self.project = Project.objects.create(
|
||||
slug='np', title='NoN Pack', category='non_pack', owner=self.alice,
|
||||
)
|
||||
self._upload_version('np', 'pack.zip', _animation_pack_zip()) # jakebreath:testpack
|
||||
other = _zip_bytes({
|
||||
'pack.mcmeta': json.dumps({'pack': {'pack_format': 64},
|
||||
'animationframework': {'id': 'other:pack'}}),
|
||||
'data/other/afw_animdefs/x.json': '{}',
|
||||
})
|
||||
# Without confirmation → form error, no new version.
|
||||
self.gate()
|
||||
self.client.login(username='Alice', password='pw')
|
||||
self.client.post(reverse('library:api_upload_temp'),
|
||||
{'kind': 'version', 'file': SimpleUploadedFile('other.zip', other, content_type='application/zip')},
|
||||
HTTP_X_REQUESTED_WITH='XMLHttpRequest')
|
||||
resp = self.client.post(reverse('library:version_upload', args=['np']), {'version_name': '2.0.0'})
|
||||
self.assertEqual(resp.status_code, 200)
|
||||
self.assertEqual(self.project.versions.count(), 1)
|
||||
# With confirmation → accepted.
|
||||
resp = self.client.post(reverse('library:version_upload', args=['np']),
|
||||
{'version_name': '2.0.0', 'confirm_replace_identity': '1'})
|
||||
self.assertRedirects(resp, reverse('library:project_detail', args=['np']))
|
||||
self.assertEqual(self.project.versions.count(), 2)
|
||||
self.assertEqual(self.project.versions.first().animation_id, 'other:pack')
|
||||
|
||||
def test_non_non_pack_not_injected(self):
|
||||
self.project = Project.objects.create(
|
||||
slug='mod', title='A Mod', category='mod', owner=self.alice,
|
||||
)
|
||||
self._upload_version('mod', 'pack.zip', _logical_zip())
|
||||
version = self.project.versions.first()
|
||||
self.assertEqual(version.animation_id, '')
|
||||
self.assertNotIn('animationframework', _stored_mcmeta(version))
|
||||
|
||||
def test_regenerate_metadata(self):
|
||||
self.project = Project.objects.create(
|
||||
slug='np', title='NoN Pack', category='non_pack', owner=self.alice,
|
||||
)
|
||||
self._upload_version('np', 'pack.zip', _logical_zip())
|
||||
version = self.project.versions.first()
|
||||
self.assertTrue(version.animation_id) # auto-injected at upload
|
||||
self.gate()
|
||||
self.client.login(username='Alice', password='pw')
|
||||
resp = self.client.post(reverse('library:regenerate_metadata', args=['np']),
|
||||
{'af_namespace': 'foo', 'af_pack_id': 'bar'})
|
||||
self.assertRedirects(resp, reverse('library:project_edit', args=['np']))
|
||||
version.refresh_from_db()
|
||||
self.assertEqual(version.animation_id, 'foo:bar')
|
||||
mc = _stored_mcmeta(version)
|
||||
self.assertEqual(mc['animationframework']['id'], 'foo:bar')
|
||||
resp = self.client.get(reverse('library:api_packs_latest', args=['foo', 'bar']))
|
||||
self.assertEqual(resp.status_code, 200)
|
||||
self.assertEqual(resp.json()['version'], '1.0.0')
|
||||
# Regenerated download is intact (FileIndex size refreshed).
|
||||
release = version.files.first()
|
||||
resp = self.client.get(reverse('library:file_request', args=[release.file.uuid]))
|
||||
served = b''.join(resp.streaming_content)
|
||||
self.assertEqual(int(resp['Content-Length']), release.file.size)
|
||||
self.assertEqual(len(served), release.file.size)
|
||||
with zipfile.ZipFile(io.BytesIO(served)) as zf:
|
||||
self.assertIsNone(zf.testzip())
|
||||
|
||||
def test_regenerate_validates_id(self):
|
||||
self.project = Project.objects.create(
|
||||
slug='np', title='NoN Pack', category='non_pack', owner=self.alice,
|
||||
)
|
||||
self._upload_version('np', 'pack.zip', _logical_zip())
|
||||
before = self.project.versions.first().animation_id
|
||||
self.gate()
|
||||
self.client.login(username='Alice', password='pw')
|
||||
resp = self.client.post(reverse('library:regenerate_metadata', args=['np']),
|
||||
{'af_namespace': 'bad id!', 'af_pack_id': 'bar'})
|
||||
self.assertRedirects(resp, reverse('library:project_edit', args=['np']))
|
||||
self.project.versions.first().refresh_from_db()
|
||||
self.assertEqual(self.project.versions.first().animation_id, before)
|
||||
|
||||
def test_create_injects_defaults(self):
|
||||
self.gate()
|
||||
self.client.login(username='Alice', password='pw')
|
||||
self.client.post(reverse('library:api_upload_temp'),
|
||||
{'kind': 'version', 'file': SimpleUploadedFile('pack.zip', _logical_zip(), content_type='application/zip')},
|
||||
HTTP_X_REQUESTED_WITH='XMLHttpRequest')
|
||||
resp = self.client.post(reverse('library:project_create'), {
|
||||
'title': 'New Pack', 'category': 'non_pack', 'version_name': '1.0.0',
|
||||
})
|
||||
self.assertRedirects(resp, reverse('library:project_detail', args=['new-pack']))
|
||||
project = Project.objects.get(slug='new-pack')
|
||||
version = project.versions.first()
|
||||
self.assertEqual(version.animation_id, f'alice:project_{project.pk}')
|
||||
|
||||
Reference in New Issue
Block a user