1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169
|
# -*- coding: utf-8 -*-
# vim: ts=4 sw=4 tw=88 et ai si
#
# Copyright (c) 2012-2014 Intel, Inc.
# License: GPLv2
# Author: Artem Bityutskiy <artem.bityutskiy@linux.intel.com>
#
# This program is free software; you can redistribute it and/or modify
# it under the terms of the GNU General Public License, version 2,
# as published by the Free Software Foundation.
#
# This program is distributed in the hope that it will be useful, but
# WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
# General Public License for more details.
"""
This test verifies 'Filemap' module functionality. It generates random sparse
files and makes sure the module returns correct information about the holes.
"""
# Disable the following pylint recommendations:
# * Too many public methods - R0904
# * Too many arguments - R0913
# pylint: disable=R0904
# pylint: disable=R0913
import sys
import random
import itertools
import tests.helpers
from itertools import zip_longest
from bmaptool import Filemap
# This is a work-around for Centos 6
try:
import unittest2 as unittest # pylint: disable=F0401
except ImportError:
import unittest
class Error(Exception):
"""A class for exceptions generated by this test."""
pass
def _check_ranges(f_image, filemap, first_block, blocks_cnt, ranges, ranges_type):
"""
This is a helper function for '_do_test()' which compares the correct
'ranges' list of mapped or unmapped blocks ranges for file object 'f_image'
with what the 'Filemap' module reports. The 'ranges_type' argument defines
whether the 'ranges' list is a list of mapped or unmapped blocks. The
'first_block' and 'blocks_cnt' define the subset of blocks in 'f_image'
that should be verified by this function.
"""
if ranges_type == "mapped":
filemap_iterator = filemap.get_mapped_ranges(first_block, blocks_cnt)
elif ranges_type == "unmapped":
filemap_iterator = filemap.get_unmapped_ranges(first_block, blocks_cnt)
else:
raise Error("incorrect list type")
last_block = first_block + blocks_cnt - 1
# The 'ranges' list contains all ranges, from block zero to the last
# block. However, we are conducting a test for 'blocks_cnt' of blocks
# starting from block 'first_block'. Create an iterator which filters
# those block ranges from the 'ranges' list, that are out of the
# 'first_block'/'blocks_cnt' file region.
ranges_iterator = (x for x in ranges if x[1] >= first_block and x[0] <= last_block)
iterator = zip_longest(ranges_iterator, filemap_iterator)
# Iterate over both - the (filtered) 'ranges' list which contains correct
# ranges and the Filemap generator, and verify the mapped/unmapped ranges
# returned by the 'Filemap' module.
for correct, check in iterator:
# The first and the last range of the filtered 'ranges' list may still
# be out of the limit - correct them in this case
if correct[0] < first_block:
correct = (first_block, correct[1])
if correct[1] > last_block:
correct = (correct[0], last_block)
if check[0] > check[1] or check != correct:
raise Error(
"bad or mismatching %s range for file '%s': correct "
"is %d-%d, get_%s_ranges(%d, %d) returned %d-%d"
% (
ranges_type,
f_image.name,
correct[0],
correct[1],
ranges_type,
first_block,
blocks_cnt,
check[0],
check[1],
)
)
for block in range(correct[0], correct[1] + 1):
if ranges_type == "mapped" and filemap.block_is_unmapped(block):
raise Error(
"range %d-%d of file '%s' is mapped, but"
"'block_is_unmapped(%d) returned 'True'"
% (correct[0], correct[1], f_image.name, block)
)
if ranges_type == "unmapped" and filemap.block_is_mapped(block):
raise Error(
"range %d-%d of file '%s' is unmapped, but"
"'block_is_mapped(%d) returned 'True'"
% (correct[0], correct[1], f_image.name, block)
)
def _do_test(f_image, filemap, mapped, unmapped):
"""
Verify that the 'Filemap' module provides correct mapped and unmapped areas
for the 'f_image' file object. The 'mapped' and 'unmapped' lists contain
the correct ranges. The 'filemap' is one of the classed from the 'Filemap'
module.
"""
# Check both 'get_mapped_ranges()' and 'get_unmapped_ranges()' for the
# entire file.
first_block = 0
blocks_cnt = filemap.blocks_cnt
_check_ranges(f_image, filemap, first_block, blocks_cnt, mapped, "mapped")
_check_ranges(f_image, filemap, first_block, blocks_cnt, unmapped, "unmapped")
# Select a random area in the file and repeat the test few times
for _ in range(0, 10):
first_block = random.randint(0, filemap.blocks_cnt - 1)
blocks_cnt = random.randint(1, filemap.blocks_cnt - first_block)
_check_ranges(f_image, filemap, first_block, blocks_cnt, mapped, "mapped")
_check_ranges(f_image, filemap, first_block, blocks_cnt, unmapped, "unmapped")
class TestFilemap(unittest.TestCase):
"""
The test class for this unit tests. Basically executes the '_do_test()'
function for different sparse files.
"""
def test(self): # pylint: disable=R0201
"""
The test entry point. Executes the '_do_test()' function for files of
different sizes, holes distribution and format.
"""
# Delete all the test-related temporary files automatically
delete = True
# Create all the test-related temporary files in current directory
directory = "."
# Maximum size of the random files used in this test
max_size = 16 * 1024 * 1024
iterator = tests.helpers.generate_test_files(max_size, directory, delete)
for f_image, _, mapped, unmapped in iterator:
try:
fiemap = Filemap.FilemapFiemap(f_image)
_do_test(f_image, fiemap, mapped, unmapped)
seek = Filemap.FilemapSeek(f_image)
_do_test(f_image, seek, mapped, unmapped)
except Filemap.ErrorNotSupp:
pass
|