1a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)# Copyright 2014 The Chromium Authors. All rights reserved.
2a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)# Use of this source code is governed by a BSD-style license that can be
3a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)# found in the LICENSE file.
4a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)
5a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)"""This unittest covers both file_storage and serialization modules."""
6a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)
7a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)import os
8a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)import tempfile
9a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)import time
10a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)import unittest
11a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)
12a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)from memory_inspector.core import memory_map
13a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)from memory_inspector.core import native_heap
14a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)from memory_inspector.core import stacktrace
15a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)from memory_inspector.core import symbol
16a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)from memory_inspector.data import file_storage
17a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)
18a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)
19a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)class FileStorageTest(unittest.TestCase):
20a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)  def setUp(self):
21a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)    self._storage_path = tempfile.mkdtemp()
22a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)    self._storage = file_storage.Storage(self._storage_path)
23a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)
24a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)  def tearDown(self):
25a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)    os.removedirs(self._storage_path)
26a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)
27a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)  def testSettings(self):
28a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)    settings_1 = { 'foo' : 1, 'bar' : 2 }
29a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)    settings_2 = { 'foo' : 1, 'bar' : 2 }
30a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)    self._storage.StoreSettings('one', settings_1)
31a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)    self._storage.StoreSettings('two', settings_2)
32a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)    self._DeepCompare(settings_1, self._storage.LoadSettings('one'))
33a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)    self._DeepCompare(settings_2, self._storage.LoadSettings('two'))
34a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)    self._storage.StoreSettings('one', {})
35a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)    self._storage.StoreSettings('two', {})
36a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)
37a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)  def testArchives(self):
38a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)    self._storage.OpenArchive('foo', create=True)
39a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)    self._storage.OpenArchive('bar', create=True)
40a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)    self._storage.OpenArchive('baz', create=True)
41a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)    self._storage.DeleteArchive('bar')
42a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)    self.assertTrue('foo' in self._storage.ListArchives())
43a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)    self.assertFalse('bar' in self._storage.ListArchives())
44a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)    self.assertTrue('baz' in self._storage.ListArchives())
45a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)    self._storage.DeleteArchive('foo')
46a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)    self._storage.DeleteArchive('baz')
47a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)
48a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)  def testSnapshots(self):
49a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)    archive = self._storage.OpenArchive('snapshots', create=True)
50a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)    t1 = archive.StartNewSnapshot()
51a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)    archive.StoreMemMaps(memory_map.Map())
52a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)    time.sleep(0.01) # Max snapshot resolution is in the order of usecs.
53a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)    t2 = archive.StartNewSnapshot()
54a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)    archive.StoreMemMaps(memory_map.Map())
55a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)    archive.StoreNativeHeap(native_heap.NativeHeap())
56a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)    self.assertIn(t1, archive.ListSnapshots())
57a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)    self.assertIn(t2, archive.ListSnapshots())
58a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)    self.assertTrue(archive.HasMemMaps(t1))
59a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)    self.assertFalse(archive.HasNativeHeap(t1))
60a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)    self.assertTrue(archive.HasMemMaps(t2))
61a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)    self.assertTrue(archive.HasNativeHeap(t2))
62a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)    self._storage.DeleteArchive('snapshots')
63a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)
64a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)  def testMmap(self):
65a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)    archive = self._storage.OpenArchive('mmap', create=True)
66a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)    timestamp = archive.StartNewSnapshot()
67a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)    mmap = memory_map.Map()
68a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)    map_entry1 = memory_map.MapEntry(4096, 8191, 'rw--', '/foo', 0)
69a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)    map_entry2 = memory_map.MapEntry(65536, 81919, 'rw--', '/bar', 4096)
70a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)    map_entry2.resident_pages = [5]
71a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)    mmap.Add(map_entry1)
72a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)    mmap.Add(map_entry2)
73a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)    archive.StoreMemMaps(mmap)
74a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)    mmap_deser = archive.LoadMemMaps(timestamp)
75a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)    self._DeepCompare(mmap, mmap_deser)
76a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)    self._storage.DeleteArchive('mmap')
77a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)
78a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)  def testNativeHeap(self):
79a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)    archive = self._storage.OpenArchive('nheap', create=True)
80a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)    timestamp = archive.StartNewSnapshot()
81a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)    nh = native_heap.NativeHeap()
82a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)    for i in xrange(1, 4):
83a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)      stack_trace = stacktrace.Stacktrace()
84a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)      frame = nh.GetStackFrame(i * 10 + 1)
85a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)      frame.SetExecFileInfo('foo.so', 1)
86a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)      stack_trace.Add(frame)
87a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)      frame = nh.GetStackFrame(i * 10 + 2)
88a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)      frame.SetExecFileInfo('bar.so', 2)
89a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)      stack_trace.Add(frame)
901320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci      nh.Add(native_heap.Allocation(size=i * 10,
911320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci                                    stack_trace=stack_trace,
921320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci                                    start=i * 20,
931320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci                                    flags=i * 30))
94a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)    archive.StoreNativeHeap(nh)
95a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)    nh_deser = archive.LoadNativeHeap(timestamp)
96a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)    self._DeepCompare(nh, nh_deser)
97a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)    self._storage.DeleteArchive('nheap')
98a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)
99a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)  def testSymbols(self):
100a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)    archive = self._storage.OpenArchive('symbols', create=True)
101a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)    symbols = symbol.Symbols()
102a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)    # Symbol db is global per archive, no need to StartNewSnapshot.
103a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)    symbols.Add('foo.so', 1, symbol.Symbol('sym1', 'file1.c', 11))
104a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)    symbols.Add('bar.so', 2, symbol.Symbol('sym2', 'file2.c', 12))
105a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)    sym3 = symbol.Symbol('sym3', 'file2.c', 13)
106a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)    sym3.AddSourceLineInfo('outer_file.c', 23)
107a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)    symbols.Add('baz.so', 3, sym3)
108a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)    archive.StoreSymbols(symbols)
109a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)    symbols_deser = archive.LoadSymbols()
110a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)    self._DeepCompare(symbols, symbols_deser)
111a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)    self._storage.DeleteArchive('symbols')
112a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)
113a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)  def _DeepCompare(self, a, b, prefix=''):
114a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)    """Recursively compares two objects (original and deserialized)."""
115a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)
116a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)    self.assertEqual(a is None, b is None)
117a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)    if a is None:
118a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)      return
119a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)
1201320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci    _BASICTYPES = (long, int, basestring, float)
121a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)    if isinstance(a, _BASICTYPES) and isinstance(b, _BASICTYPES):
122a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)      return self.assertEqual(a, b, prefix)
123a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)
124a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)    self.assertEqual(type(a), type(b), prefix + ' type (%s vs %s' % (
125a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)        type(a), type(b)))
126a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)
127a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)    if isinstance(a, list):
128a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)      self.assertEqual(len(a), len(b), prefix + ' len (%d vs %d)' % (
129a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)          len(a), len(b)))
130a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)      for i in range(len(a)):
131a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)        self._DeepCompare(a[i], b[i], prefix + '[%d]' % i)
132a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)      return
133a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)
134a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)    if isinstance(a, dict):
135a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)      self.assertEqual(a.keys(), b.keys(), prefix + ' keys (%s vs %s)' % (
136a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)        str(a.keys()), str(b.keys())))
137a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)      for k in a.iterkeys():
138a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)        self._DeepCompare(a[k], b[k], prefix + '.' + str(k))
139a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)      return
140a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)
141a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)    return self._DeepCompare(a.__dict__, b.__dict__, prefix)