1#!/usr/bin/env python3 2# 3# Copyright 2019, The Android Open Source Project 4# 5# Licensed under the Apache License, Version 2.0 (the "License"); 6# you may not use this file except in compliance with the License. 7# You may obtain a copy of the License at 8# 9# http://www.apache.org/licenses/LICENSE-2.0 10# 11# Unless required by applicable law or agreed to in writing, software 12# distributed under the License is distributed on an "AS IS" BASIS, 13# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 14# See the License for the specific language governing permissions and 15# limitations under the License. 16# 17 18""" 19Unit tests for inode2filename module. 20 21Install: 22 $> sudo apt-get install python3-pytest ## OR 23 $> pip install -U pytest 24See also https://docs.pytest.org/en/latest/getting-started.html 25 26Usage: 27 $> ./inode2filename_test.py 28 $> pytest inode2filename_test.py 29 $> python -m pytest inode2filename_test.py 30 31See also https://docs.pytest.org/en/latest/usage.html 32""" 33 34# global imports 35import io 36from copy import deepcopy 37 38# pip imports 39# local imports 40from trace2db import * 41 42# This pretty-prints the raw dictionary of the sqlalchemy object if it fails. 43class EqualsSqlAlchemyObject: 44 # For convenience to write shorter tests, we also add 'ignore_fields' which allow us to specify 45 # which fields to ignore when doing the comparison. 46 def __init__(self_, self, ignore_fields=[]): 47 self_.self = self 48 self_.ignore_fields = ignore_fields 49 50 # Do field-by-field comparison. 51 # It seems that SQLAlchemy does not implement __eq__ itself so we have to do it ourselves. 52 def __eq__(self_, other): 53 if isinstance(other, EqualsSqlAlchemyObject): 54 other = other.self 55 56 self = self_.self 57 58 classes_match = isinstance(other, self.__class__) 59 a, b = deepcopy(self.__dict__), deepcopy(other.__dict__) 60 61 #compare based on equality our attributes, ignoring SQLAlchemy internal stuff 62 63 a.pop('_sa_instance_state', None) 64 b.pop('_sa_instance_state', None) 65 66 for f in self_.ignore_fields: 67 a.pop(f, None) 68 b.pop(f, None) 69 70 attrs_match = (a == b) 71 return classes_match and attrs_match 72 73 def __repr__(self): 74 return repr(self.self.__dict__) 75 76 77def assert_eq_ignore_id(left, right): 78 # This pretty-prints the raw dictionary of the sqlalchemy object if it fails. 79 # It does field-by-field comparison, but ignores the 'id' field. 80 assert EqualsSqlAlchemyObject(left, ignore_fields=['id']) == EqualsSqlAlchemyObject(right) 81 82def parse_trace_file_to_db(*contents): 83 """ 84 Make temporary in-memory sqlite3 database by parsing the string contents as a trace. 85 86 :return: Trace2Db instance 87 """ 88 buf = io.StringIO() 89 90 for c in contents: 91 buf.write(c) 92 buf.write("\n") 93 94 buf.seek(0) 95 96 t2d = Trace2Db(":memory:") 97 t2d.parse_file_buf_into_db(buf) 98 99 buf.close() 100 101 return t2d 102 103def test_ftrace_mm_filemap_add_to_pagecache(): 104 test_contents = """ 105MediaStoreImpor-27212 (27176) [000] .... 16136.595194: mm_filemap_add_to_page_cache: dev 253:6 ino 7580 page=0000000060e990c7 pfn=677646 ofs=159744 106MediaStoreImpor-27212 (27176) [000] .... 16136.595920: mm_filemap_add_to_page_cache: dev 253:6 ino 7580 page=0000000048e2e156 pfn=677645 ofs=126976 107MediaStoreImpor-27212 (27176) [000] .... 16136.597793: mm_filemap_add_to_page_cache: dev 253:6 ino 7580 page=0000000051eabfb2 pfn=677644 ofs=122880 108MediaStoreImpor-27212 (27176) [000] .... 16136.597815: mm_filemap_add_to_page_cache: dev 253:6 ino 7580 page=00000000ce7cd606 pfn=677643 ofs=131072 109MediaStoreImpor-27212 (27176) [000] .... 16136.603732: mm_filemap_add_to_page_cache: dev 253:6 ino 1 page=000000008ffd3030 pfn=730119 ofs=186482688 110MediaStoreImpor-27212 (27176) [000] .... 16136.604126: mm_filemap_add_to_page_cache: dev 253:6 ino b1d8 page=0000000098d4d2e2 pfn=829676 ofs=0 111 <...>-27197 (-----) [002] .... 16136.613471: mm_filemap_add_to_page_cache: dev 253:6 ino 7580 page=00000000aca88a97 pfn=743346 ofs=241664 112 <...>-27197 (-----) [002] .... 16136.615979: mm_filemap_add_to_page_cache: dev 253:6 ino 7580 page=00000000351f2bc1 pfn=777799 ofs=106496 113 <...>-27224 (-----) [006] .... 16137.400090: mm_filemap_add_to_page_cache: dev 253:6 ino 712d page=000000006ff7ffdb pfn=754861 ofs=0 114 <...>-1396 (-----) [000] .... 16137.451660: mm_filemap_add_to_page_cache: dev 253:6 ino 1 page=00000000ba0cbb34 pfn=769173 ofs=187191296 115 <...>-1396 (-----) [000] .... 16137.453020: mm_filemap_add_to_page_cache: dev 253:6 ino b285 page=00000000f6ef038e pfn=820291 ofs=0 116 <...>-1396 (-----) [000] .... 16137.453067: mm_filemap_add_to_page_cache: dev 253:6 ino b285 page=0000000083ebc446 pfn=956463 ofs=4096 117 <...>-1396 (-----) [000] .... 16137.453101: mm_filemap_add_to_page_cache: dev 253:6 ino b285 page=000000009dc2cd25 pfn=822813 ofs=8192 118 <...>-1396 (-----) [000] .... 16137.453113: mm_filemap_add_to_page_cache: dev 253:6 ino b285 page=00000000a11167fb pfn=928650 ofs=12288 119 <...>-1396 (-----) [000] .... 16137.453126: mm_filemap_add_to_page_cache: dev 253:6 ino b285 page=00000000c1c3311b pfn=621110 ofs=16384 120 <...>-1396 (-----) [000] .... 16137.453139: mm_filemap_add_to_page_cache: dev 253:6 ino b285 page=000000009aa78342 pfn=689370 ofs=20480 121 <...>-1396 (-----) [000] .... 16137.453151: mm_filemap_add_to_page_cache: dev 253:6 ino b285 page=0000000082cddcd6 pfn=755584 ofs=24576 122 <...>-1396 (-----) [000] .... 16137.453162: mm_filemap_add_to_page_cache: dev 253:6 ino b285 page=00000000b0249bc7 pfn=691431 ofs=28672 123 <...>-1396 (-----) [000] .... 16137.453183: mm_filemap_add_to_page_cache: dev 253:6 ino b285 page=000000006a776ff0 pfn=795084 ofs=32768 124 <...>-1396 (-----) [000] .... 16137.453203: mm_filemap_add_to_page_cache: dev 253:6 ino b285 page=000000001a4918a7 pfn=806998 ofs=36864 125 <...>-2578 (-----) [002] .... 16137.561871: mm_filemap_add_to_page_cache: dev 253:6 ino 1 page=00000000d65af9d2 pfn=719246 ofs=187015168 126 <...>-2578 (-----) [002] .... 16137.562846: mm_filemap_add_to_page_cache: dev 253:6 ino b25a page=000000002f6ba74f pfn=864982 ofs=0 127 <...>-2578 (-----) [000] .... 16138.104500: mm_filemap_add_to_page_cache: dev 253:6 ino 1 page=00000000f888d0f6 pfn=805812 ofs=192794624 128 <...>-2578 (-----) [000] .... 16138.105836: mm_filemap_add_to_page_cache: dev 253:6 ino b7dd page=000000003749523b pfn=977196 ofs=0 129 <...>-27215 (-----) [001] .... 16138.256881: mm_filemap_add_to_page_cache: dev 253:6 ino 758f page=000000001b375de1 pfn=755928 ofs=0 130 <...>-27215 (-----) [001] .... 16138.257526: mm_filemap_add_to_page_cache: dev 253:6 ino 7591 page=000000004e039481 pfn=841534 ofs=0 131 NonUserFacing6-5246 ( 1322) [005] .... 16138.356491: mm_filemap_add_to_page_cache: dev 253:6 ino 1 page=00000000d65af9d2 pfn=719246 ofs=161890304 132 NonUserFacing6-5246 ( 1322) [005] .... 16138.357538: mm_filemap_add_to_page_cache: dev 253:6 ino 9a64 page=000000002f6ba74f pfn=864982 ofs=0 133 NonUserFacing6-5246 ( 1322) [005] .... 16138.357581: mm_filemap_add_to_page_cache: dev 253:6 ino 9a64 page=000000006e0f8322 pfn=797894 ofs=4096 134 <...>-27197 (-----) [005] .... 16140.143224: mm_filemap_add_to_page_cache: dev 253:6 ino 7580 page=00000000a42527c6 pfn=1076669 ofs=32768 135 """ 136 137 t2d = parse_trace_file_to_db(test_contents) 138 session = t2d.session 139 140 first_row = session.query(MmFilemapAddToPageCache).order_by(MmFilemapAddToPageCache.id).first() 141 142 #dev 253:6 ino 7580 page=0000000060e990c7 pfn=677646 ofs=159744 143 assert_eq_ignore_id(MmFilemapAddToPageCache(dev=64774, dev_major=253, dev_minor=6, 144 ino=0x7580, page=0x0000000060e990c7, pfn=677646, ofs=159744), first_row) 145 146 second_to_last_row = session.query(MmFilemapAddToPageCache).filter(MmFilemapAddToPageCache.page.in_([0x000000006e0f8322])).first() 147 148 # dev 253:6 ino 9a64 page=000000006e0f8322 pfn=797894 ofs=4096 149 assert_eq_ignore_id(MmFilemapAddToPageCache(dev=64774, dev_major=253, dev_minor=6, 150 ino=0x9a64, page=0x000000006e0f8322, pfn=797894, ofs=4096), second_to_last_row) 151 152def test_systrace_mm_filemap_add_to_pagecache(): 153 test_contents = """ 154<!DOCTYPE html> 155<html> 156<head i18n-values="dir:textdirection;"> 157<meta http-equiv="Content-Type" content="text/html; charset=utf-8"> 158<meta charset="utf-8"/> 159<title>Android System Trace</title> 160 <script class="trace-data" type="application/text"> 161PROCESS DUMP 162USER PID PPID VSZ RSS WCHAN PC S NAME COMM 163root 1 0 62148 5976 0 0 S init [init] 164root 2 0 0 0 0 0 S [kthreadd] [kthreadd] 165 </script> 166 167 <script class="trace-data" type="application/text"> 168MediaStoreImpor-27212 (27176) [000] .... 16136.595194: mm_filemap_add_to_page_cache: dev 253:6 ino 7580 page=0000000060e990c7 pfn=677646 ofs=159744 169NonUserFacing6-5246 ( 1322) [005] .... 16138.357581: mm_filemap_add_to_page_cache: dev 253:6 ino 9a64 page=000000006e0f8322 pfn=797894 ofs=4096 170 </script> 171 172 <script class="trace-data" type="application/text"> 173{"traceEvents": [{"category": "process_argv", "name": "process_argv", "args": {"argv": ["/mnt/ssd3/workspace/master/external/chromium-trace/systrace.py", "-t", "5", "pagecache"]}, "pid": 160383, "ts": 1037300940509.7991, "tid": 139628672526080, "ph": "M"}, {"category": "python", "name": "clock_sync", "args": {"issue_ts": 1037307346185.212, "sync_id": "9a7e4fe3-89ad-441f-8226-8fe533fe973e"}, "pid": 160383, "ts": 1037307351643.906, "tid": 139628726089536, "ph": "c"}], "metadata": {"clock-domain": "SYSTRACE"}} 174 </script> 175<!-- END TRACE --> 176 """ 177 178 t2d = parse_trace_file_to_db(test_contents) 179 session = t2d.session 180 181 first_row = session.query(MmFilemapAddToPageCache).order_by(MmFilemapAddToPageCache.id).first() 182 183 #dev 253:6 ino 7580 page=0000000060e990c7 pfn=677646 ofs=159744 184 assert_eq_ignore_id(MmFilemapAddToPageCache(dev=64774, dev_major=253, dev_minor=6, 185 ino=0x7580, page=0x0000000060e990c7, pfn=677646, ofs=159744), first_row) 186 187 second_to_last_row = session.query(MmFilemapAddToPageCache).filter(MmFilemapAddToPageCache.page.in_([0x000000006e0f8322])).first() 188 189 # dev 253:6 ino 9a64 page=000000006e0f8322 pfn=797894 ofs=4096 190 assert_eq_ignore_id(MmFilemapAddToPageCache(dev=64774, dev_major=253, dev_minor=6, 191 ino=0x9a64, page=0x000000006e0f8322, pfn=797894, ofs=4096), second_to_last_row) 192 193def test_timestamp_filter(): 194 test_contents = """ 195 MediaStoreImpor-27212 (27176) [000] .... 16136.595194: mm_filemap_add_to_page_cache: dev 253:6 ino 7580 page=0000000060e990c7 pfn=677646 ofs=159744 196 NonUserFacing6-5246 ( 1322) [005] .... 16139.357581: mm_filemap_add_to_page_cache: dev 253:6 ino 9a64 page=000000006e0f8322 pfn=797894 ofs=4096 197 MediaStoreImpor-27212 (27176) [000] .... 16136.604126: mm_filemap_add_to_page_cache: dev 253:6 ino b1d8 page=0000000098d4d2e2 pfn=829676 ofs=0 198 """ 199 200 t2d = parse_trace_file_to_db(test_contents) 201 session = t2d.session 202 203 end_time = 16137.0 204 205 results = session.query(MmFilemapAddToPageCache).join( 206 MmFilemapAddToPageCache.raw_ftrace_entry).filter( 207 RawFtraceEntry.timestamp <= end_time).order_by( 208 MmFilemapAddToPageCache.id).all() 209 210 assert len(results) == 2 211 assert_eq_ignore_id( 212 MmFilemapAddToPageCache(dev=64774, dev_major=253, dev_minor=6, 213 ino=0x7580, page=0x0000000060e990c7, pfn=677646, 214 ofs=159744), results[0]) 215 assert_eq_ignore_id( 216 MmFilemapAddToPageCache(dev=64774, dev_major=253, dev_minor=6, 217 ino=0xb1d8, page=0x0000000098d4d2e2, pfn=829676, 218 ofs=0), results[1]) 219 220 221if __name__ == '__main__': 222 pytest.main() 223