diff --git a/test/py/tests/test_fs/conftest.py b/test/py/tests/test_fs/conftest.py
index 71abf8fa4222..6404b311bc30 100644
--- a/test/py/tests/test_fs/conftest.py
+++ b/test/py/tests/test_fs/conftest.py
@@ -12,6 +12,7 @@ from fstest_defs import *
 supported_fs_basic = ['fat16', 'fat32', 'ext4']
 supported_fs_ext = ['fat16', 'fat32']
 supported_fs_mkdir = ['fat16', 'fat32']
+supported_fs_unlink = ['fat16', 'fat32']
 
 #
 # Filesystem test specific setup
@@ -24,6 +25,7 @@ def pytest_configure(config):
     global supported_fs_basic
     global supported_fs_ext
     global supported_fs_mkdir
+    global supported_fs_unlink
 
     def intersect(listA, listB):
         return  [x for x in listA if x in listB]
@@ -34,6 +36,7 @@ def pytest_configure(config):
         supported_fs_basic =  intersect(supported_fs, supported_fs_basic)
         supported_fs_ext =  intersect(supported_fs, supported_fs_ext)
         supported_fs_mkdir =  intersect(supported_fs, supported_fs_mkdir)
+        supported_fs_unlink =  intersect(supported_fs, supported_fs_unlink)
 
 def pytest_generate_tests(metafunc):
     if 'fs_obj_basic' in metafunc.fixturenames:
@@ -45,6 +48,9 @@ def pytest_generate_tests(metafunc):
     if 'fs_obj_mkdir' in metafunc.fixturenames:
         metafunc.parametrize('fs_obj_mkdir', supported_fs_mkdir,
             indirect=True, scope='module')
+    if 'fs_obj_unlink' in metafunc.fixturenames:
+        metafunc.parametrize('fs_obj_unlink', supported_fs_unlink,
+            indirect=True, scope='module')
 
 #
 # Helper functions
@@ -328,3 +334,59 @@ def fs_obj_mkdir(request, u_boot_config):
     finally:
         if fs_img:
             call('rm -f %s' % fs_img, shell=True)
+
+#
+# Fixture for unlink test
+#
+# NOTE: yield_fixture was deprecated since pytest-3.0
+@pytest.yield_fixture()
+def fs_obj_unlink(request, u_boot_config):
+    fs_type = request.param
+    fs_img = ''
+
+    fs_ubtype = fstype_to_ubname(fs_type)
+    check_ubconfig(u_boot_config, fs_ubtype)
+
+    mount_dir = u_boot_config.persistent_data_dir + '/mnt'
+
+    try:
+
+        # 128MiB volume
+        fs_img = mk_fs(u_boot_config, fs_type, 0x8000000, '128MB')
+
+        # Mount the image so we can populate it.
+        check_call('mkdir -p %s' % mount_dir, shell=True)
+        mount_fs(fs_type, fs_img, mount_dir)
+
+        # Test Case 1 & 3
+        check_call('mkdir %s/dir1' % mount_dir, shell=True)
+        check_call('dd if=/dev/urandom of=%s/dir1/file1 bs=1K count=1'
+                                    % mount_dir, shell=True)
+        check_call('dd if=/dev/urandom of=%s/dir1/file2 bs=1K count=1'
+                                    % mount_dir, shell=True)
+
+        # Test Case 2
+        check_call('mkdir %s/dir2' % mount_dir, shell=True)
+	for i in range(0, 20):
+	    check_call('mkdir %s/dir2/0123456789abcdef%02x'
+                                    % (mount_dir, i), shell=True)
+
+        # Test Case 4
+        check_call('mkdir %s/dir4' % mount_dir, shell=True)
+
+        # Test Case 5, 6 & 7
+        check_call('mkdir %s/dir5' % mount_dir, shell=True)
+        check_call('dd if=/dev/urandom of=%s/dir5/file1 bs=1K count=1'
+                                    % mount_dir, shell=True)
+
+        umount_fs(fs_type, mount_dir)
+    except CalledProcessError:
+        pytest.skip('Setup failed for filesystem: ' + fs_type)
+        return
+    else:
+        yield [fs_ubtype, fs_img]
+    finally:
+        umount_fs(fs_type, mount_dir)
+        call('rmdir %s' % mount_dir, shell=True)
+        if fs_img:
+            call('rm -f %s' % fs_img, shell=True)
diff --git a/test/py/tests/test_fs/test_unlink.py b/test/py/tests/test_fs/test_unlink.py
new file mode 100644
index 000000000000..69c1a6e078c3
--- /dev/null
+++ b/test/py/tests/test_fs/test_unlink.py
@@ -0,0 +1,109 @@
+# SPDX-License-Identifier:      GPL-2.0+
+# Copyright (c) 2018, Linaro Limited
+# Author: Takahiro Akashi <takahiro.akashi@linaro.org>
+#
+# U-Boot File System:unlink Test
+
+"""
+This test verifies unlink operation (deleting a file or a directory)
+on file system.
+"""
+
+import pytest
+
+@pytest.mark.boardspec('sandbox')
+class TestUnlink(object):
+    def test_unlink1(self, u_boot_console, fs_obj_unlink):
+        """
+        Test Case 1 - delete a file
+        """
+        fs_type,fs_img = fs_obj_unlink
+        with u_boot_console.log.section('Test Case 1 - unlink (file)'):
+            output = u_boot_console.run_command_list([
+                'host bind 0 %s' % fs_img,
+                '%srm host 0:0 dir1/file1' % fs_type,
+                '%sls host 0:0 dir1/file1' % fs_type])
+            assert('' == ''.join(output))
+
+            output = u_boot_console.run_command(
+                '%sls host 0:0 dir1/' % fs_type)
+            assert(not 'file1' in output)
+            assert('file2' in output)
+
+    def test_unlink2(self, u_boot_console, fs_obj_unlink):
+        """
+        Test Case 2 - delete many files
+        """
+        fs_type,fs_img = fs_obj_unlink
+        with u_boot_console.log.section('Test Case 2 - unlink (many)'):
+            output = u_boot_console.run_command('host bind 0 %s' % fs_img)
+
+            for i in range(0, 20):
+                output = u_boot_console.run_command_list([
+                    '%srm host 0:0 dir2/0123456789abcdef%02x' % (fs_type, i),
+                    '%sls host 0:0 dir2/0123456789abcdef%02x' % (fs_type, i)])
+                assert('' == ''.join(output))
+
+            output = u_boot_console.run_command(
+                '%sls host 0:0 dir2' % fs_type)
+            assert('0 file(s), 2 dir(s)' in output)
+
+    def test_unlink3(self, u_boot_console, fs_obj_unlink):
+        """
+        Test Case 3 - trying to delete a non-existing file should fail
+        """
+        fs_type,fs_img = fs_obj_unlink
+        with u_boot_console.log.section('Test Case 3 - unlink (non-existing)'):
+            output = u_boot_console.run_command_list([
+                'host bind 0 %s' % fs_img,
+                '%srm host 0:0 dir1/nofile' % fs_type])
+            assert('nofile: doesn\'t exist' in ''.join(output))
+
+    def test_unlink4(self, u_boot_console, fs_obj_unlink):
+        """
+        Test Case 4 - delete an empty directory
+        """
+        fs_type,fs_img = fs_obj_unlink
+        with u_boot_console.log.section('Test Case 4 - unlink (directory)'):
+            output = u_boot_console.run_command_list([
+                'host bind 0 %s' % fs_img,
+                '%srm host 0:0 dir4' % fs_type])
+            assert('' == ''.join(output))
+
+        output = u_boot_console.run_command(
+            '%sls host 0:0 /' % fs_type)
+        assert(not 'dir4' in output)
+
+    def test_unlink5(self, u_boot_console, fs_obj_unlink):
+        """
+        Test Case 5 - trying to deleting a non-empty directory ".."
+        should fail
+        """
+        fs_type,fs_img = fs_obj_unlink
+        with u_boot_console.log.section('Test Case 5 - unlink ("non-empty directory")'):
+            output = u_boot_console.run_command_list([
+                'host bind 0 %s' % fs_img,
+                '%srm host 0:0 dir5' % fs_type])
+            assert('directory is not empty' in ''.join(output))
+
+    def test_unlink6(self, u_boot_console, fs_obj_unlink):
+        """
+        Test Case 6 - trying to deleting a "." should fail
+        """
+        fs_type,fs_img = fs_obj_unlink
+        with u_boot_console.log.section('Test Case 6 - unlink (".")'):
+            output = u_boot_console.run_command_list([
+                'host bind 0 %s' % fs_img,
+                '%srm host 0:0 dir5/.' % fs_type])
+            assert('directory is not empty' in ''.join(output))
+
+    def test_unlink7(self, u_boot_console, fs_obj_unlink):
+        """
+        Test Case 7 - trying to deleting a ".." should fail
+        """
+        fs_type,fs_img = fs_obj_unlink
+        with u_boot_console.log.section('Test Case 7 - unlink ("..")'):
+            output = u_boot_console.run_command_list([
+                'host bind 0 %s' % fs_img,
+                '%srm host 0:0 dir5/..' % fs_type])
+            assert('directory is not empty' in ''.join(output))
