From 97861eaa285a60d710b355ab8aff1b5e950d82fa Mon Sep 17 00:00:00 2001 From: Jordan Owens Date: Tue, 31 May 2016 16:11:03 -0400 Subject: [PATCH] Extract recursive import specs into a shared example --- test/sqlite3/import_test.rb | 2 + test/support/postgresql/import_examples.rb | 121 +---------------- .../shared_examples/recursive_import.rb | 122 ++++++++++++++++++ 3 files changed, 126 insertions(+), 119 deletions(-) create mode 100644 test/support/shared_examples/recursive_import.rb diff --git a/test/sqlite3/import_test.rb b/test/sqlite3/import_test.rb index eeecd969..07e07ab8 100644 --- a/test/sqlite3/import_test.rb +++ b/test/sqlite3/import_test.rb @@ -1,5 +1,7 @@ require File.expand_path(File.dirname(__FILE__) + '/../test_helper') +should_support_recursive_import + describe "#supports_imports?" do context "and SQLite is 3.7.11 or higher" do it "supports import" do diff --git a/test/support/postgresql/import_examples.rb b/test/support/postgresql/import_examples.rb index 0b601cd3..9211ec40 100644 --- a/test/support/postgresql/import_examples.rb +++ b/test/support/postgresql/import_examples.rb @@ -1,5 +1,7 @@ # encoding: UTF-8 def should_support_postgresql_import_functionality + should_support_recursive_import + describe "#supports_imports?" do it "should support import" do assert ActiveRecord::Base.supports_import? @@ -18,112 +20,6 @@ def should_support_postgresql_import_functionality end end - describe "importing objects with associations" do - let(:new_topics) { Build(num_topics, :topic_with_book) } - let(:new_topics_with_invalid_chapter) do - chapter = new_topics.first.books.first.chapters.first - chapter.title = nil - new_topics - end - let(:num_topics) { 3 } - let(:num_books) { 6 } - let(:num_chapters) { 18 } - let(:num_endnotes) { 24 } - - let(:new_question_with_rule) { FactoryGirl.build :question, :with_rule } - - it 'imports top level' do - assert_difference "Topic.count", +num_topics do - Topic.import new_topics, recursive: true - new_topics.each do |topic| - assert_not_nil topic.id - end - end - end - - it 'imports first level associations' do - assert_difference "Book.count", +num_books do - Topic.import new_topics, recursive: true - new_topics.each do |topic| - topic.books.each do |book| - assert_equal topic.id, book.topic_id - end - end - end - end - - it 'imports polymorphic associations' do - discounts = Array.new(1) { |i| Discount.new(amount: i) } - books = Array.new(1) { |i| Book.new(author_name: "Author ##{i}", title: "Book ##{i}") } - books.each do |book| - book.discounts << discounts - end - Book.import books, recursive: true - books.each do |book| - book.discounts.each do |discount| - assert_not_nil discount.discountable_id - assert_equal 'Book', discount.discountable_type - end - end - end - - [{ recursive: false }, {}].each do |import_options| - it "skips recursion for #{import_options}" do - assert_difference "Book.count", 0 do - Topic.import new_topics, import_options - end - end - end - - it 'imports deeper nested associations' do - assert_difference "Chapter.count", +num_chapters do - assert_difference "EndNote.count", +num_endnotes do - Topic.import new_topics, recursive: true - new_topics.each do |topic| - topic.books.each do |book| - book.chapters.each do |chapter| - assert_equal book.id, chapter.book_id - end - book.end_notes.each do |endnote| - assert_equal book.id, endnote.book_id - end - end - end - end - end - end - - it "skips validation of the associations if requested" do - assert_difference "Chapter.count", +num_chapters do - Topic.import new_topics_with_invalid_chapter, validate: false, recursive: true - end - end - - it 'imports has_one associations' do - assert_difference 'Rule.count' do - Question.import [new_question_with_rule], recursive: true - end - end - - # These models dont validate associated. So we expect that books and topics get inserted, but not chapters - # Putting a transaction around everything wouldn't work, so if you want your chapters to prevent topics from - # being created, you would need to have validates_associated in your models and insert with validation - describe "all_or_none" do - [Book, Topic, EndNote].each do |type| - it "creates #{type}" do - assert_difference "#{type}.count", send("num_#{type.to_s.downcase}s") do - Topic.import new_topics_with_invalid_chapter, all_or_none: true, recursive: true - end - end - end - it "doesn't create chapters" do - assert_difference "Chapter.count", 0 do - Topic.import new_topics_with_invalid_chapter, all_or_none: true, recursive: true - end - end - end - end - describe "with query cache enabled" do setup do unless ActiveRecord::Base.connection.query_cache_enabled @@ -294,19 +190,6 @@ def should_support_postgresql_upsert_functionality should_update_updated_at_on_timestamp_columns end end - - context "with recursive: true" do - let(:new_topics) { Build(1, :topic_with_book) } - - it "imports objects with associations" do - assert_difference "Topic.count", +1 do - Topic.import new_topics, recursive: true, on_duplicate_key_update: [:updated_at], validate: false - new_topics.each do |topic| - assert_not_nil topic.id - end - end - end - end end end end diff --git a/test/support/shared_examples/recursive_import.rb b/test/support/shared_examples/recursive_import.rb new file mode 100644 index 00000000..feac4dfe --- /dev/null +++ b/test/support/shared_examples/recursive_import.rb @@ -0,0 +1,122 @@ +def should_support_recursive_import + describe "importing objects with associations" do + let(:new_topics) { Build(num_topics, :topic_with_book) } + let(:new_topics_with_invalid_chapter) do + chapter = new_topics.first.books.first.chapters.first + chapter.title = nil + new_topics + end + let(:num_topics) { 3 } + let(:num_books) { 6 } + let(:num_chapters) { 18 } + let(:num_endnotes) { 24 } + + let(:new_question_with_rule) { FactoryGirl.build :question, :with_rule } + + it 'imports top level' do + assert_difference "Topic.count", +num_topics do + Topic.import new_topics, recursive: true + new_topics.each do |topic| + assert_not_nil topic.id + end + end + end + + it 'imports first level associations' do + assert_difference "Book.count", +num_books do + Topic.import new_topics, recursive: true + new_topics.each do |topic| + topic.books.each do |book| + assert_equal topic.id, book.topic_id + end + end + end + end + + it 'imports polymorphic associations' do + discounts = Array.new(1) { |i| Discount.new(amount: i) } + books = Array.new(1) { |i| Book.new(author_name: "Author ##{i}", title: "Book ##{i}") } + books.each do |book| + book.discounts << discounts + end + Book.import books, recursive: true + books.each do |book| + book.discounts.each do |discount| + assert_not_nil discount.discountable_id + assert_equal 'Book', discount.discountable_type + end + end + end + + [{ recursive: false }, {}].each do |import_options| + it "skips recursion for #{import_options}" do + assert_difference "Book.count", 0 do + Topic.import new_topics, import_options + end + end + end + + it 'imports deeper nested associations' do + assert_difference "Chapter.count", +num_chapters do + assert_difference "EndNote.count", +num_endnotes do + Topic.import new_topics, recursive: true + new_topics.each do |topic| + topic.books.each do |book| + book.chapters.each do |chapter| + assert_equal book.id, chapter.book_id + end + book.end_notes.each do |endnote| + assert_equal book.id, endnote.book_id + end + end + end + end + end + end + + it "skips validation of the associations if requested" do + assert_difference "Chapter.count", +num_chapters do + Topic.import new_topics_with_invalid_chapter, validate: false, recursive: true + end + end + + it 'imports has_one associations' do + assert_difference 'Rule.count' do + Question.import [new_question_with_rule], recursive: true + end + end + + # These models dont validate associated. So we expect that books and topics get inserted, but not chapters + # Putting a transaction around everything wouldn't work, so if you want your chapters to prevent topics from + # being created, you would need to have validates_associated in your models and insert with validation + describe "all_or_none" do + [Book, Topic, EndNote].each do |type| + it "creates #{type}" do + assert_difference "#{type}.count", send("num_#{type.to_s.downcase}s") do + Topic.import new_topics_with_invalid_chapter, all_or_none: true, recursive: true + end + end + end + it "doesn't create chapters" do + assert_difference "Chapter.count", 0 do + Topic.import new_topics_with_invalid_chapter, all_or_none: true, recursive: true + end + end + end + + # If adapter supports on_duplicate_key_update, it is only applied to top level models so that SQL with invalid + # columns, keys, etc isn't generated for child associations when doing recursive import + describe "on_duplicate_key_update" do + let(:new_topics) { Build(1, :topic_with_book) } + + it "imports objects with associations" do + assert_difference "Topic.count", +1 do + Topic.import new_topics, recursive: true, on_duplicate_key_update: [:updated_at], validate: false + new_topics.each do |topic| + assert_not_nil topic.id + end + end + end + end + end +end