bitbake: tests/fetch: Test gitsm with LFS

Add a test case to verify that the gitsm fetcher properly handles
repositories storing objects with LFS.

The test case verifies that LFS objects are fetched on the initial clone
but also ensures that consecutive updates extend the original clone with
any newly referenced LFS objects.

(Bitbake rev: 2a8722ddd155596862029f6ea34e1e92c77e0b7f)

Signed-off-by: Philip Lorenz <philip.lorenz@bmw.de>
Signed-off-by: Richard Purdie <richard.purdie@linuxfoundation.org>
This commit is contained in:
Philip Lorenz 2025-04-29 10:11:24 +02:00 committed by Richard Purdie
parent 3eeac69385
commit a7331c3992

View File

@ -20,6 +20,7 @@ import tarfile
from bb.fetch2 import URI
from bb.fetch2 import FetchMethod
import bb
import bb.utils
from bb.tests.support.httpserver import HTTPService
def skipIfNoNetwork():
@ -27,6 +28,18 @@ def skipIfNoNetwork():
return unittest.skip("network test")
return lambda f: f
@contextlib.contextmanager
def hide_directory(directory):
"""Hide the given directory and restore it after the context is left"""
temp_name = directory + ".bak"
os.rename(directory, temp_name)
try:
yield
finally:
os.rename(temp_name, directory)
class TestTimeout(Exception):
# Indicate to pytest that this is not a test suite
__test__ = False
@ -2325,25 +2338,112 @@ class GitLfsTest(FetcherTest):
return unpacked_lfs_file
@skipIfNoGitLFS()
def test_fetch_lfs_on_srcrev_change(self):
"""Test if fetch downloads missing LFS objects when a different revision within an existing repository is requested"""
def test_gitsm_lfs(self):
"""Test that the gitsm fetcher caches objects stored via LFS"""
self.git(["lfs", "install", "--local"], cwd=self.srcdir)
@contextlib.contextmanager
def hide_upstream_repository():
"""Hide the upstream repository to make sure that git lfs cannot pull from it"""
temp_name = self.srcdir + ".bak"
os.rename(self.srcdir, temp_name)
try:
yield
finally:
os.rename(temp_name, self.srcdir)
def fetch_and_verify(revision, filename, content):
self.d.setVar('SRCREV', revision)
fetcher, ud = self.fetch()
with hide_upstream_repository():
with hide_directory(submoduledir), hide_directory(self.srcdir):
workdir = self.d.getVar('WORKDIR')
fetcher.unpack(workdir)
with open(os.path.join(workdir, "git", filename)) as f:
self.assertEqual(f.read(), content)
# Create the git repository that will later be used as a submodule
submoduledir = self.tempdir + "/submodule"
bb.utils.mkdirhier(submoduledir)
self.git_init(submoduledir)
self.git(["lfs", "install", "--local"], cwd=submoduledir)
self.commit_file('.gitattributes', '*.mp3 filter=lfs -text', cwd=submoduledir)
submodule_commit_1 = self.commit_file("a.mp3", "submodule version 1", cwd=submoduledir)
_ = self.commit_file("a.mp3", "submodule version 2", cwd=submoduledir)
# Add the submodule to the repository at its current HEAD revision
self.git(["-c", "protocol.file.allow=always", "submodule", "add", submoduledir, "submodule"],
cwd=self.srcdir)
base_commit_1 = self.commit()
# Let the submodule point at a different revision
self.git(["checkout", submodule_commit_1], self.srcdir + "/submodule")
self.git(["add", "submodule"], cwd=self.srcdir)
base_commit_2 = self.commit()
# Add a LFS file to the repository
base_commit_3 = self.commit_file("a.mp3", "version 1")
# Update the added LFS file
base_commit_4 = self.commit_file("a.mp3", "version 2")
self.d.setVar('SRC_URI', "gitsm://%s;protocol=file;lfs=1;branch=master" % self.srcdir)
# Verify that LFS objects referenced from submodules are fetched and checked out
fetch_and_verify(base_commit_1, "submodule/a.mp3", "submodule version 2")
# Verify that the repository inside the download cache of a submodile is extended with any
# additional LFS objects needed when checking out a different revision.
fetch_and_verify(base_commit_2, "submodule/a.mp3", "submodule version 1")
# Verify that LFS objects referenced from the base repository are fetched and checked out
fetch_and_verify(base_commit_3, "a.mp3", "version 1")
# Verify that the cached repository is extended with any additional LFS objects required
# when checking out a different revision.
fetch_and_verify(base_commit_4, "a.mp3", "version 2")
@skipIfNoGitLFS()
def test_gitsm_lfs_disabled(self):
"""Test that the gitsm fetcher does not use LFS when explicitly disabled"""
self.git(["lfs", "install", "--local"], cwd=self.srcdir)
def fetch_and_verify(revision, filename, content):
self.d.setVar('SRCREV', revision)
fetcher, ud = self.fetch()
with hide_directory(submoduledir), hide_directory(self.srcdir):
workdir = self.d.getVar('WORKDIR')
fetcher.unpack(workdir)
with open(os.path.join(workdir, "git", filename)) as f:
# Assume that LFS did not perform smudging when the expected content is
# missing.
self.assertNotEqual(f.read(), content)
# Create the git repository that will later be used as a submodule
submoduledir = self.tempdir + "/submodule"
bb.utils.mkdirhier(submoduledir)
self.git_init(submoduledir)
self.git(["lfs", "install", "--local"], cwd=submoduledir)
self.commit_file('.gitattributes', '*.mp3 filter=lfs -text', cwd=submoduledir)
submodule_commit_1 = self.commit_file("a.mp3", "submodule version 1", cwd=submoduledir)
# Add the submodule to the repository at its current HEAD revision
self.git(["-c", "protocol.file.allow=always", "submodule", "add", submoduledir, "submodule"],
cwd=self.srcdir)
base_commit_1 = self.commit()
# Add a LFS file to the repository
base_commit_2 = self.commit_file("a.mp3", "version 1")
self.d.setVar('SRC_URI', "gitsm://%s;protocol=file;lfs=1;branch=master;lfs=0" % self.srcdir)
# Verify that LFS objects referenced from submodules are not fetched nor checked out
fetch_and_verify(base_commit_1, "submodule/a.mp3", "submodule version 1")
# Verify that the LFS objects referenced from the base repository are not fetched nor
# checked out
fetch_and_verify(base_commit_2, "a.mp3", "version 1")
@skipIfNoGitLFS()
def test_fetch_lfs_on_srcrev_change(self):
"""Test if fetch downloads missing LFS objects when a different revision within an existing repository is requested"""
self.git(["lfs", "install", "--local"], cwd=self.srcdir)
def fetch_and_verify(revision, filename, content):
self.d.setVar('SRCREV', revision)
fetcher, ud = self.fetch()
with hide_directory(self.srcdir):
workdir = self.d.getVar('WORKDIR')
fetcher.unpack(workdir)