1#!/usr/bin/env python 2# Copyright 2013 The Chromium Authors. All rights reserved. 3# Use of this source code is governed by a BSD-style license that can be 4# found in the LICENSE file. 5 6import json 7import unittest 8 9from compiled_file_system import CompiledFileSystem 10from object_store_creator import ObjectStoreCreator 11from redirector import Redirector 12from test_file_system import TestFileSystem 13from third_party.json_schema_compiler.json_parse import Parse 14 15HOST = 'http://localhost/' 16 17file_system = TestFileSystem({ 18 'redirects.json': json.dumps({ 19 'foo/...': 'apps/...', 20 '': '/index.html', 21 'home': 'index.html', 22 'index.html': 'http://something.absolute.com/' 23 }), 24 'apps': { 25 'redirects.json': json.dumps({ 26 '': '../index.html', 27 'index.html': 'about_apps.html', 28 'foo.html': '/bar.html', 29 }) 30 }, 31 'extensions': { 32 'redirects.json': json.dumps({ 33 'manifest': 'manifest.html', 34 'tabs': 'tabs.html', 35 'dev/...': '...', 36 'a/very/long/dir/chain/...': 'short/...', 37 '_short/...': 'another/long/chain/...', 38 'r1/...': 'r2/r1/...', 39 'r2/r1/...': 'r3/...', 40 'r3/...': 'r4/...', 41 'r5/...': 'r6/...', 42 'nofile1/...': 'nofile2/...', 43 'noredirects1/...': 'noredirects2/...' 44 }), 45 'manifest': { 46 'redirects.json': json.dumps({ 47 '': '../manifest.html', 48 'more-info': 'http://lmgtfy.com' 49 }), 50 }, 51 'stable': { 52 'redirects.json': json.dumps({ 53 'tabs': 'tabs.html' 54 }), 55 'manifest': { 56 'redirects.json': json.dumps({ 57 'storage': 'storage.html' 58 }) 59 }, 60 }, 61 'dev': { 62 'redirects.json': json.dumps({ 63 'tabs': 'tabs.html', 64 'manifest': 'manifest.html' 65 }), 66 'manifest': { 67 'redirects.json': json.dumps({ 68 'storage': 'storage.html' 69 }) 70 } 71 }, 72 'r4': { 73 'redirects.json': json.dumps({ 74 'manifest': 'manifest.html' 75 }) 76 }, 77 'r6': { 78 'redirects.json': json.dumps({ 79 '...': 'directory/...' 80 }), 81 'directory': { 82 'redirects.json': json.dumps({ 83 'manifest': 'manifest.html' 84 }), 85 'manifest': 'manifest.html' 86 } 87 }, 88 'short': { 89 'redirects.json': json.dumps({ 90 'index': 'index.html' 91 }) 92 }, 93 'another': { 94 'long': { 95 'chain': { 96 'redirects.json': json.dumps({ 97 'index': 'index.html' 98 }) 99 } 100 } 101 }, 102 'nofile': { 103 'redirects.json': json.dumps({ 104 }) 105 } 106 }, 107 'priority': { 108 'redirects.json': json.dumps({ 109 'directory/...': 'GOOD/...' 110 }), 111 'directory': { 112 'redirects.json': json.dumps({ 113 '...': '../BAD/...' 114 }), 115 } 116 }, 117 'relative_directory': { 118 'redirects.json': json.dumps({ 119 '...': '../...' 120 }) 121 }, 122 'infinite_redirect': { 123 'redirects.json': json.dumps({ 124 '...': 'loop/...' 125 }), 126 'loop': { 127 'redirects.json': json.dumps({ 128 '...': './...' 129 }) 130 } 131 }, 132 'parent_redirect': { 133 'redirects.json': json.dumps({ 134 'a/...': 'b/...' 135 }) 136 } 137}) 138 139class RedirectorTest(unittest.TestCase): 140 def setUp(self): 141 self._redirector = Redirector( 142 CompiledFileSystem.Factory(ObjectStoreCreator.ForTest()), 143 file_system) 144 145 def testExternalRedirection(self): 146 self.assertEqual( 147 'http://something.absolute.com/', 148 self._redirector.Redirect(HOST, 'index.html')) 149 self.assertEqual( 150 'http://lmgtfy.com', 151 self._redirector.Redirect(HOST, 'extensions/manifest/more-info')) 152 153 def testAbsoluteRedirection(self): 154 self.assertEqual( 155 '/index.html', self._redirector.Redirect(HOST, '')) 156 self.assertEqual( 157 '/bar.html', self._redirector.Redirect(HOST, 'apps/foo.html')) 158 159 def testRelativeRedirection(self): 160 self.assertEqual( 161 'apps/about_apps.html', 162 self._redirector.Redirect(HOST, 'apps/index.html')) 163 self.assertEqual( 164 'extensions/manifest.html', 165 self._redirector.Redirect(HOST, 'extensions/manifest/')) 166 self.assertEqual( 167 'extensions/manifest.html', 168 self._redirector.Redirect(HOST, 'extensions/manifest')) 169 self.assertEqual( 170 'index.html', self._redirector.Redirect(HOST, 'apps/')) 171 self.assertEqual( 172 'index.html', self._redirector.Redirect(HOST, 'home')) 173 174 def testNotFound(self): 175 self.assertEqual( 176 None, self._redirector.Redirect(HOST, 'not/a/real/path')) 177 self.assertEqual( 178 None, self._redirector.Redirect(HOST, 'public/apps/okay.html')) 179 180 def testOldHosts(self): 181 self.assertEqual( 182 'https://developer.chrome.com/', 183 self._redirector.Redirect('http://code.google.com', '')) 184 self.assertEqual( 185 'https://developer.chrome.com/', 186 self._redirector.Redirect('https://code.google.com', '')) 187 188 def testRefresh(self): 189 self._redirector.Refresh().Get() 190 191 expected_paths = set([ 192 'redirects.json', 193 'apps/redirects.json', 194 'extensions/redirects.json', 195 'extensions/manifest/redirects.json' 196 ]) 197 198 for path in expected_paths: 199 self.assertEqual( 200 Parse(file_system.ReadSingle(path).Get()), 201 # Access the cache's object store to see what files were hit during 202 # the cron run. Returns strings parsed as JSON. 203 # TODO(jshumway): Make a non hack version of this check. 204 self._redirector._cache._file_object_store.Get( 205 path).Get().cache_data) 206 207 def testDirectoryRedirection(self): 208 # Simple redirect. 209 self.assertEqual( 210 'extensions/manifest.html', 211 self._redirector.Redirect(HOST, 'extensions/dev/manifest')) 212 213 # Multiple hops with one file. 214 self.assertEqual( 215 'extensions/r4/manifest.html', 216 self._redirector.Redirect(HOST, 'extensions/r1/manifest')) 217 218 # Multiple hops w/ multiple redirection files. 219 self.assertEqual( 220 'extensions/r6/directory/manifest.html', 221 self._redirector.Redirect(HOST, 'extensions/r5/manifest')) 222 223 # Redirection from root directory redirector. 224 self.assertEqual( 225 'apps/about_apps.html', 226 self._redirector.Redirect(HOST, 'foo/index.html')) 227 228 # Short to long. 229 self.assertEqual( 230 'extensions/short/index.html', 231 self._redirector.Redirect(HOST, 'extensions/a/very/long/dir/chain/index')) 232 233 # Long to short. 234 self.assertEqual( 235 'extensions/another/long/chain/index.html', 236 self._redirector.Redirect(HOST, 'extensions/_short/index')) 237 238 # Directory redirection without a redirects.json in final directory. 239 self.assertEqual( 240 'extensions/noredirects2/file', 241 self._redirector.Redirect(HOST, 'extensions/noredirects1/file')) 242 243 # Directory redirection with redirects.json without rule for the filename. 244 self.assertEqual( 245 'extensions/nofile2/file', 246 self._redirector.Redirect(HOST, 'extensions/nofile1/file')) 247 248 # Relative directory path. 249 self.assertEqual( 250 'index.html', 251 self._redirector.Redirect(HOST, 'relative_directory/home')) 252 253 # Shallower directory redirects have priority. 254 self.assertEqual( 255 'priority/GOOD/index', 256 self._redirector.Redirect(HOST, 'priority/directory/index')) 257 258 # Don't infinitely redirect. 259 self.assertEqual('infinite_redirect/loop/index', 260 self._redirector.Redirect(HOST, 'infinite_redirect/index')) 261 262 # If a parent directory is redirected, redirect children properly. 263 self.assertEqual('parent_redirect/b/c/index', 264 self._redirector.Redirect(HOST, 'parent_redirect/a/c/index')) 265 266 267if __name__ == '__main__': 268 unittest.main() 269