PageRenderTime 44ms CodeModel.GetById 12ms RepoModel.GetById 0ms app.codeStats 0ms

/vendor/plugins/efficient-sql/test/assert_efficient_sql_test.rb

https://github.com/grantneufeld/wayground-old
Ruby | 238 lines | 144 code | 39 blank | 55 comment | 0 complexity | dcf7389e94b3232d96154b9b17b188cf MD5 | raw file
  1. #:stopdoc:
  2. require 'rubygems'
  3. require 'active_record'
  4. require 'test/unit'
  5. require 'assert_efficient_sql'
  6. require 'yaml'
  7. require 'optparse'
  8. require 'erb'
  9. require 'pathname'
  10. #:startdoc:
  11. class AssertEfficientSqlTest < Test::Unit::TestCase
  12. def setup #:nodoc:
  13. config_file = (rails_root + 'config/database.yml').to_s
  14. config = YAML.load(ERB.new(IO.read(config_file)).result)['test']
  15. ActiveRecord::Base.establish_connection(config)
  16. ActiveRecord::Base.connection.
  17. create_table(:foos) do |t|
  18. t.column :name, :string, :limit => 60
  19. end
  20. 43.times{ Foo.create!(:name => 'whatever') }
  21. end
  22. # If +assert_efficient_sql+ (generally) dislikes your arguments,
  23. # it will print out its default options, each with an explanation
  24. #
  25. def test_help
  26. assert_stdout /invalid.*argument.*
  27. verbose.*=\>.*false/mx do
  28. assert_efficient_sql(:help){}
  29. end
  30. end
  31. def test_assert_efficient_sql
  32. assert_efficient_sql{ Foo.find(2) }
  33. end
  34. # If your SQL is already efficient, use <b>:verbose</b> to diagnose
  35. # <i>why</i> it's efficient.
  36. #
  37. def test_verbose
  38. assert_stdout /select_type/ do
  39. assert_efficient_sql :verbose do
  40. Foo.find_by_id(42)
  41. end
  42. end
  43. end
  44. # If your block did not call any SQL SELECT statements,
  45. # you probably need a warning!
  46. #
  47. def test_require_sql
  48. assert_flunked /no queries/ do
  49. assert_efficient_sql{}
  50. end
  51. end
  52. # This test case uses
  53. # <code>assert_raise_message[http://www.oreillynet.com/onlamp/blog/2007/07/assert_raise_on_ruby_dont_just.html]</code>
  54. # to demonstrate <code>assert_efficient_sql</code> failing:
  55. #
  56. def test_assert_inefficient_sql
  57. assert_flunked /Pessimistic.*
  58. full.table.scan.*
  59. Foo.Load/mx do
  60. assert_efficient_sql do
  61. Foo.find_by_sql('select * from foos a')
  62. end
  63. end
  64. end
  65. # One common pessimization is a query that reads thousands
  66. # of rows just to return a few. +assert_efficient_sql+
  67. # counts the rows hit in each phase of an SQL +SELECT+,
  68. # and faults if any row count exceeds <b>1,000</b>.
  69. #
  70. # Adjust this count with <b><code>:throttle => 42</code></b>.
  71. #
  72. def test_throttle
  73. 101.times{|x| Foo.create :name => "foo_#{ x }" }
  74. assert_flunked /Pessimistic.*
  75. more.than.*100.*
  76. Foo.Load/mx do
  77. assert_efficient_sql :throttle => 100, :ALL => true do
  78. Foo.find(:all)
  79. end
  80. end
  81. end
  82. # Sometimes you need an +ALL+, even while other <code>assert_efficient_sql</code>
  83. # checks must pass. To positively declare we like +ALL+, pass it as the key of a
  84. # +true+ option into the assertion:
  85. #
  86. def test_assert_all
  87. assert_efficient_sql :ALL => true do
  88. Foo.find(:all)
  89. end
  90. end
  91. # If your +WHERE+ and +ORDER+ clauses are too complex,
  92. # MySQL might need to write a file (or worse), just to
  93. # satisfy a query. +assert_efficient_sql+ detects this
  94. # pernicious situation:
  95. #
  96. def test_prevent_filesorts
  97. _exec %[ CREATE TABLE `t1` (
  98. `a` int(11) NOT NULL DEFAULT '0',
  99. `b` blob NOT NULL,
  100. `c` text NOT NULL,
  101. PRIMARY KEY (`a`,`b`(255),`c`(255)),
  102. KEY `t1ba` (`b`(10),`a`)
  103. ) ENGINE=InnoDB ]
  104. assert_flunked /Using.filesort/ do
  105. assert_efficient_sql do
  106. Foo.find_by_sql('SELECT a FROM t1 ORDER BY b')
  107. end
  108. end
  109. ensure
  110. _exec 'drop table t1' # ERGO if exist
  111. end
  112. def test_ALL_with_possible_keys
  113. _exec %[ CREATE TABLE `t2` (
  114. `a` int(11) NOT NULL DEFAULT '0',
  115. `b` blob,
  116. `c` int(11) NOT NULL,
  117. PRIMARY KEY (a)
  118. ) ENGINE=InnoDB ]
  119. assert_efficient_sql :ALL => true, :Using_filesort => true, :key => false do
  120. Foo.find_by_sql('SELECT a FROM t2 ORDER BY c')
  121. end
  122. ensure
  123. ActiveRecord::Base.connection.drop_table(:t2) rescue nil
  124. end
  125. def test_with_keys
  126. # FIXME
  127. end
  128. # <code>assert_efficient_sql</code> calls
  129. # <code>SHOW SESSION STATUS</code> before and after
  130. # its sampled block. If you are seeking an advanced
  131. # pessimization, such as <code>Created_tmp_disk_tables</code>,
  132. # pass <code>:Created_tmp_disk_tables => 0</code>. The
  133. # assertion will compare difference in STATUS before
  134. # and after calling its block. A difference greater
  135. # than the allowed difference will trigger a fault.
  136. #
  137. # To test this, we simply detect a STATUS variable
  138. # which is not a warning.
  139. #
  140. def test_declare_futile_war_on_Innodb_rows_read
  141. assert_flunked /just.for.test.*
  142. Innodb_rows_read/mx do
  143. assert_efficient_sql :diagnostic => 'just for test!',
  144. :Innodb_rows_read => 0 do
  145. Foo.find(:all)
  146. end
  147. end
  148. end
  149. # You can also nest the assertion, to provide different
  150. # options for different blocks. The assertion allows
  151. # this because your test might also have some other
  152. # reason to use blocks
  153. #
  154. def test_nest
  155. outer_result = assert_efficient_sql do
  156. inner_result = assert_efficient_sql :ALL => true do
  157. Foo.find(:all)
  158. end
  159. assert_no_match /where/i, inner_result[0][0]
  160. Foo.find(42)
  161. end
  162. assert_match /where/i, outer_result[0][0]
  163. end
  164. def assert_flunked(gripe, &block) #:nodoc:
  165. assert_raise_message Test::Unit::AssertionFailedError, gripe, &block
  166. end # ERGO move to assert{ 2.0 }, reflect, and leave there!
  167. def teardown #:nodoc:
  168. ActiveRecord::Base.connection.drop_table(:foos) rescue nil
  169. end
  170. end
  171. #:enddoc:
  172. class AssertNonMysqlTest < Test::Unit::TestCase
  173. # The assertion requires MySQL. To peacefully coexist with
  174. # test rigs that use multiple adapters, we only warn, once,
  175. # if MySQL is not found. If you don't need this warning,
  176. # turn it off with :warn_mysql_required => false
  177. #
  178. def test_gently_forwarn_non_mysql_connectors
  179. ActiveRecord::Base.establish_connection( :adapter => 'sqlite3',
  180. :dbfile => ':memory:' )
  181. deny_stdout /requires MySQL/, 'disabled warning' do
  182. assert_efficient_sql :warn_mysql_required => false
  183. end
  184. assert_stdout /requires MySQL/, 'warn the first time' do
  185. assert_efficient_sql
  186. end
  187. deny_stdout /requires MySQL/, 'don\'t warn the second time' do
  188. assert_efficient_sql
  189. end
  190. ensure
  191. config_file = (rails_root + 'config/database.yml').to_s
  192. config = YAML.load(ERB.new(IO.read(config_file)).result)['test']
  193. ActiveRecord::Base.establish_connection(config)
  194. end
  195. end
  196. class Foo < ActiveRecord::Base; end
  197. def rails_root # ERGO is this used?
  198. return (Pathname.new(__FILE__).expand_path.dirname + '../../../..').expand_path
  199. end