32
31
from bzrlib.tests import (
33
32
TestCaseWithTransport,
35
split_suite_by_condition,
38
load_tests = scenarios.load_tests_apply_scenarios
41
def btreeparser_scenarios():
37
from bzrlib.transport import get_transport
40
def load_tests(standard_tests, module, loader):
41
# parameterise the TestBTreeNodes tests
42
node_tests, others = split_suite_by_condition(standard_tests,
43
condition_isinstance(TestBTreeNodes))
42
44
import bzrlib._btree_serializer_py as py_module
43
45
scenarios = [('python', {'parse_btree': py_module})]
44
46
if compiled_btreeparser_feature.available():
45
scenarios.append(('C',
46
{'parse_btree': compiled_btreeparser_feature.module}))
47
scenarios.append(('C', {'parse_btree':
48
compiled_btreeparser_feature.module}))
49
return multiply_tests(node_tests, scenarios, others)
50
52
compiled_btreeparser_feature = tests.ModuleAvailableFeature(
51
'bzrlib._btree_serializer_pyx')
53
'bzrlib._btree_serializer_pyx')
54
56
class BTreeTestCase(TestCaseWithTransport):
605
607
for key, value, references in nodes:
606
608
builder.add_node(key, value, references)
607
609
stream = builder.finish()
608
trans = transport.get_transport('trace+' + self.get_url())
610
trans = get_transport('trace+' + self.get_url())
609
611
size = trans.put_file('index', stream)
610
612
return btree_index.BTreeGraphIndex(trans, 'index', size)
612
def make_index_with_offset(self, ref_lists=1, key_elements=1, nodes=[],
614
builder = btree_index.BTreeBuilder(key_elements=key_elements,
615
reference_lists=ref_lists)
616
builder.add_nodes(nodes)
617
transport = self.get_transport('')
618
# NamedTemporaryFile dies on builder.finish().read(). weird.
619
temp_file = builder.finish()
620
content = temp_file.read()
623
transport.put_bytes('index', (' '*offset)+content)
624
return btree_index.BTreeGraphIndex(transport, 'index', size=size,
627
614
def test_clear_cache(self):
628
615
nodes = self.make_nodes(160, 2, 2)
629
616
index = self.make_index(ref_lists=2, key_elements=2, nodes=nodes)
646
633
self.assertEqual(0, len(index._leaf_node_cache))
648
635
def test_trivial_constructor(self):
649
t = transport.get_transport('trace+' + self.get_url(''))
650
index = btree_index.BTreeGraphIndex(t, 'index', None)
636
transport = get_transport('trace+' + self.get_url(''))
637
index = btree_index.BTreeGraphIndex(transport, 'index', None)
651
638
# Checks the page size at load, but that isn't logged yet.
652
self.assertEqual([], t._activity)
639
self.assertEqual([], transport._activity)
654
641
def test_with_size_constructor(self):
655
t = transport.get_transport('trace+' + self.get_url(''))
656
index = btree_index.BTreeGraphIndex(t, 'index', 1)
642
transport = get_transport('trace+' + self.get_url(''))
643
index = btree_index.BTreeGraphIndex(transport, 'index', 1)
657
644
# Checks the page size at load, but that isn't logged yet.
658
self.assertEqual([], t._activity)
645
self.assertEqual([], transport._activity)
660
647
def test_empty_key_count_no_size(self):
661
648
builder = btree_index.BTreeBuilder(key_elements=1, reference_lists=0)
662
t = transport.get_transport('trace+' + self.get_url(''))
663
t.put_file('index', builder.finish())
664
index = btree_index.BTreeGraphIndex(t, 'index', None)
666
self.assertEqual([], t._activity)
649
transport = get_transport('trace+' + self.get_url(''))
650
transport.put_file('index', builder.finish())
651
index = btree_index.BTreeGraphIndex(transport, 'index', None)
652
del transport._activity[:]
653
self.assertEqual([], transport._activity)
667
654
self.assertEqual(0, index.key_count())
668
655
# The entire index should have been requested (as we generally have the
669
656
# size available, and doing many small readvs is inappropriate).
670
657
# We can't tell how much was actually read here, but - check the code.
671
self.assertEqual([('get', 'index')], t._activity)
658
self.assertEqual([('get', 'index')], transport._activity)
673
660
def test_empty_key_count(self):
674
661
builder = btree_index.BTreeBuilder(key_elements=1, reference_lists=0)
675
t = transport.get_transport('trace+' + self.get_url(''))
676
size = t.put_file('index', builder.finish())
662
transport = get_transport('trace+' + self.get_url(''))
663
size = transport.put_file('index', builder.finish())
677
664
self.assertEqual(72, size)
678
index = btree_index.BTreeGraphIndex(t, 'index', size)
680
self.assertEqual([], t._activity)
665
index = btree_index.BTreeGraphIndex(transport, 'index', size)
666
del transport._activity[:]
667
self.assertEqual([], transport._activity)
681
668
self.assertEqual(0, index.key_count())
682
669
# The entire index should have been read, as 4K > size
683
670
self.assertEqual([('readv', 'index', [(0, 72)], False, None)],
686
673
def test_non_empty_key_count_2_2(self):
687
674
builder = btree_index.BTreeBuilder(key_elements=2, reference_lists=2)
688
675
nodes = self.make_nodes(35, 2, 2)
689
676
for node in nodes:
690
677
builder.add_node(*node)
691
t = transport.get_transport('trace+' + self.get_url(''))
692
size = t.put_file('index', builder.finish())
693
index = btree_index.BTreeGraphIndex(t, 'index', size)
695
self.assertEqual([], t._activity)
678
transport = get_transport('trace+' + self.get_url(''))
679
size = transport.put_file('index', builder.finish())
680
index = btree_index.BTreeGraphIndex(transport, 'index', size)
681
del transport._activity[:]
682
self.assertEqual([], transport._activity)
696
683
self.assertEqual(70, index.key_count())
697
684
# The entire index should have been read, as it is one page long.
698
685
self.assertEqual([('readv', 'index', [(0, size)], False, None)],
700
687
self.assertEqual(1173, size)
702
def test_with_offset_no_size(self):
703
index = self.make_index_with_offset(key_elements=1, ref_lists=1,
705
nodes=self.make_nodes(200, 1, 1))
706
index._size = None # throw away the size info
707
self.assertEqual(200, index.key_count())
709
def test_with_small_offset(self):
710
index = self.make_index_with_offset(key_elements=1, ref_lists=1,
712
nodes=self.make_nodes(200, 1, 1))
713
self.assertEqual(200, index.key_count())
715
def test_with_large_offset(self):
716
index = self.make_index_with_offset(key_elements=1, ref_lists=1,
718
nodes=self.make_nodes(200, 1, 1))
719
self.assertEqual(200, index.key_count())
721
689
def test__read_nodes_no_size_one_page_reads_once(self):
722
690
self.make_index(nodes=[(('key',), 'value', ())])
723
trans = transport.get_transport('trace+' + self.get_url())
691
trans = get_transport('trace+' + self.get_url())
724
692
index = btree_index.BTreeGraphIndex(trans, 'index', None)
725
693
del trans._activity[:]
726
694
nodes = dict(index._read_nodes([0]))
727
695
self.assertEqual([0], nodes.keys())
729
self.assertEqual([('key',)], node.all_keys())
697
self.assertEqual([('key',)], node.keys.keys())
730
698
self.assertEqual([('get', 'index')], trans._activity)
732
700
def test__read_nodes_no_size_multiple_pages(self):
745
713
nodes = self.make_nodes(160, 2, 2)
746
714
for node in nodes:
747
715
builder.add_node(*node)
748
t = transport.get_transport('trace+' + self.get_url(''))
749
size = t.put_file('index', builder.finish())
716
transport = get_transport('trace+' + self.get_url(''))
717
size = transport.put_file('index', builder.finish())
750
718
self.assertEqual(17692, size)
751
index = btree_index.BTreeGraphIndex(t, 'index', size)
753
self.assertEqual([], t._activity)
719
index = btree_index.BTreeGraphIndex(transport, 'index', size)
720
del transport._activity[:]
721
self.assertEqual([], transport._activity)
754
722
self.assertEqual(320, index.key_count())
755
723
# The entire index should not have been read.
756
724
self.assertEqual([('readv', 'index', [(0, 4096)], False, None)],
759
727
def test_validate_one_page(self):
760
728
builder = btree_index.BTreeBuilder(key_elements=2, reference_lists=2)
761
729
nodes = self.make_nodes(45, 2, 2)
762
730
for node in nodes:
763
731
builder.add_node(*node)
764
t = transport.get_transport('trace+' + self.get_url(''))
765
size = t.put_file('index', builder.finish())
766
index = btree_index.BTreeGraphIndex(t, 'index', size)
768
self.assertEqual([], t._activity)
732
transport = get_transport('trace+' + self.get_url(''))
733
size = transport.put_file('index', builder.finish())
734
index = btree_index.BTreeGraphIndex(transport, 'index', size)
735
del transport._activity[:]
736
self.assertEqual([], transport._activity)
770
738
# The entire index should have been read linearly.
771
739
self.assertEqual([('readv', 'index', [(0, size)], False, None)],
773
741
self.assertEqual(1488, size)
775
743
def test_validate_two_pages(self):
777
745
nodes = self.make_nodes(80, 2, 2)
778
746
for node in nodes:
779
747
builder.add_node(*node)
780
t = transport.get_transport('trace+' + self.get_url(''))
781
size = t.put_file('index', builder.finish())
748
transport = get_transport('trace+' + self.get_url(''))
749
size = transport.put_file('index', builder.finish())
782
750
# Root page, 2 leaf pages
783
751
self.assertEqual(9339, size)
784
index = btree_index.BTreeGraphIndex(t, 'index', size)
786
self.assertEqual([], t._activity)
752
index = btree_index.BTreeGraphIndex(transport, 'index', size)
753
del transport._activity[:]
754
self.assertEqual([], transport._activity)
788
756
# The entire index should have been read linearly.
790
[('readv', 'index', [(0, 4096)], False, None),
791
('readv', 'index', [(4096, 4096), (8192, 1147)], False, None)],
757
self.assertEqual([('readv', 'index', [(0, 4096)], False, None),
758
('readv', 'index', [(4096, 4096), (8192, 1147)], False, None)],
793
760
# XXX: TODO: write some badly-ordered nodes, and some pointers-to-wrong
794
761
# node and make validate find them.
796
763
def test_eq_ne(self):
797
764
# two indices are equal when constructed with the same parameters:
798
t1 = transport.get_transport('trace+' + self.get_url(''))
799
t2 = self.get_transport()
801
btree_index.BTreeGraphIndex(t1, 'index', None) ==
802
btree_index.BTreeGraphIndex(t1, 'index', None))
804
btree_index.BTreeGraphIndex(t1, 'index', 20) ==
805
btree_index.BTreeGraphIndex(t1, 'index', 20))
807
btree_index.BTreeGraphIndex(t1, 'index', 20) ==
808
btree_index.BTreeGraphIndex(t2, 'index', 20))
810
btree_index.BTreeGraphIndex(t1, 'inde1', 20) ==
811
btree_index.BTreeGraphIndex(t1, 'inde2', 20))
813
btree_index.BTreeGraphIndex(t1, 'index', 10) ==
814
btree_index.BTreeGraphIndex(t1, 'index', 20))
816
btree_index.BTreeGraphIndex(t1, 'index', None) !=
817
btree_index.BTreeGraphIndex(t1, 'index', None))
819
btree_index.BTreeGraphIndex(t1, 'index', 20) !=
820
btree_index.BTreeGraphIndex(t1, 'index', 20))
822
btree_index.BTreeGraphIndex(t1, 'index', 20) !=
823
btree_index.BTreeGraphIndex(t2, 'index', 20))
825
btree_index.BTreeGraphIndex(t1, 'inde1', 20) !=
826
btree_index.BTreeGraphIndex(t1, 'inde2', 20))
828
btree_index.BTreeGraphIndex(t1, 'index', 10) !=
829
btree_index.BTreeGraphIndex(t1, 'index', 20))
765
transport1 = get_transport('trace+' + self.get_url(''))
766
transport2 = get_transport(self.get_url(''))
768
btree_index.BTreeGraphIndex(transport1, 'index', None) ==
769
btree_index.BTreeGraphIndex(transport1, 'index', None))
771
btree_index.BTreeGraphIndex(transport1, 'index', 20) ==
772
btree_index.BTreeGraphIndex(transport1, 'index', 20))
774
btree_index.BTreeGraphIndex(transport1, 'index', 20) ==
775
btree_index.BTreeGraphIndex(transport2, 'index', 20))
777
btree_index.BTreeGraphIndex(transport1, 'inde1', 20) ==
778
btree_index.BTreeGraphIndex(transport1, 'inde2', 20))
780
btree_index.BTreeGraphIndex(transport1, 'index', 10) ==
781
btree_index.BTreeGraphIndex(transport1, 'index', 20))
783
btree_index.BTreeGraphIndex(transport1, 'index', None) !=
784
btree_index.BTreeGraphIndex(transport1, 'index', None))
786
btree_index.BTreeGraphIndex(transport1, 'index', 20) !=
787
btree_index.BTreeGraphIndex(transport1, 'index', 20))
789
btree_index.BTreeGraphIndex(transport1, 'index', 20) !=
790
btree_index.BTreeGraphIndex(transport2, 'index', 20))
792
btree_index.BTreeGraphIndex(transport1, 'inde1', 20) !=
793
btree_index.BTreeGraphIndex(transport1, 'inde2', 20))
795
btree_index.BTreeGraphIndex(transport1, 'index', 10) !=
796
btree_index.BTreeGraphIndex(transport1, 'index', 20))
831
798
def test_iter_all_only_root_no_size(self):
832
799
self.make_index(nodes=[(('key',), 'value', ())])
833
t = transport.get_transport('trace+' + self.get_url(''))
834
index = btree_index.BTreeGraphIndex(t, 'index', None)
800
trans = get_transport('trace+' + self.get_url(''))
801
index = btree_index.BTreeGraphIndex(trans, 'index', None)
802
del trans._activity[:]
836
803
self.assertEqual([(('key',), 'value')],
837
804
[x[1:] for x in index.iter_all_entries()])
838
self.assertEqual([('get', 'index')], t._activity)
805
self.assertEqual([('get', 'index')], trans._activity)
840
807
def test_iter_all_entries_reads(self):
841
808
# iterating all entries reads the header, then does a linear