diff --git a/Gemfile.lock b/Gemfile.lock index 17705ea..517e66c 100644 --- a/Gemfile.lock +++ b/Gemfile.lock @@ -1,7 +1,7 @@ PATH remote: . specs: - s3_multipart (0.0.10.5) + s3_multipart (0.0.10.6) uuid (>= 2.3.6) xml-simple (>= 1.1.2) @@ -70,6 +70,9 @@ GEM multi_json (~> 1.0) ffi (1.2.0) fssm (0.2.9) + generator_spec (0.9.3) + activesupport (>= 3.0.0) + railties (>= 3.0.0) hike (1.2.1) i18n (0.6.1) journey (1.0.4) @@ -147,17 +150,17 @@ GEM rack (~> 1.0) tilt (~> 1.1, != 1.3.0) sqlite3 (1.3.6) - systemu (2.6.4) + systemu (2.6.5) thor (0.16.0) tilt (1.3.3) treetop (1.4.12) polyglot polyglot (>= 0.3.1) tzinfo (0.3.35) - uuid (2.3.7) + uuid (2.3.8) macaddr (~> 1.0) websocket (1.0.6) - xml-simple (1.1.3) + xml-simple (1.1.5) xpath (1.0.0) nokogiri (~> 1.3) @@ -171,6 +174,7 @@ DEPENDENCIES coffee-rails (~> 3.2.1) combustion (~> 0.3.3) compass-rails + generator_spec jquery-ui-rails rails rspec-rails (~> 2.14, >= 2.14.2) diff --git a/lib/generators/s3_multipart/install_generator.rb b/lib/generators/s3_multipart/install_generator.rb index b79336a..ce80a2e 100644 --- a/lib/generators/s3_multipart/install_generator.rb +++ b/lib/generators/s3_multipart/install_generator.rb @@ -1,13 +1,18 @@ +require_relative 'migration_existence_validation_helper.rb' require 'rails/generators' module S3Multipart class InstallGenerator < Rails::Generators::Base + include MigrationExistenceValidationHelper + desc "Generates all the necessary setup for integration with the S3 Multipart gem" source_root File.expand_path("../templates", __FILE__) def create_migrations - copy_file "uploads_table_migration.rb", "db/migrate/#{migration_time}_create_s3_multipart_uploads.rb" + prompt_if_exists for_file: migration_name, to_execute: ->{ + copy_file "uploads_table_migration.rb", "db/migrate/#{migration_time}_#{migration_name}.rb" + } end def create_configuration_files @@ -18,6 +23,10 @@ def create_configuration_files private + def migration_name + 'create_s3_multipart_uploads' + end + def migration_time Time.now.strftime("%Y%m%d%H%M%S") end @@ -25,6 +34,5 @@ def migration_time def model_constant model.split("_").map(&:capitalize).join() end - end end diff --git a/lib/generators/s3_multipart/install_new_migrations_generator.rb b/lib/generators/s3_multipart/install_new_migrations_generator.rb index 70a4fab..2d63d07 100644 --- a/lib/generators/s3_multipart/install_new_migrations_generator.rb +++ b/lib/generators/s3_multipart/install_new_migrations_generator.rb @@ -1,14 +1,22 @@ +require_relative 'migration_existence_validation_helper.rb' require 'rails/generators' module S3Multipart class InstallNewMigrationsGenerator < Rails::Generators::Base + include MigrationExistenceValidationHelper + desc "Generates the migrations necessary when updating the gem to the latest version" source_root File.expand_path("../templates", __FILE__) def create_latest_migrations - copy_file "add_size_column_to_s3_multipart_uploads.rb", "db/migrate/#{migration_time}_add_size_to_s3_multipart_uploads.rb" - copy_file "add_context_column_to_s3_multipart_uploads.rb", "db/migrate/#{migration_time}_add_context_to_s3_multipart_uploads.rb" + prompt_if_exists for_file: size_column_migration_name, to_execute: ->{ + copy_file "#{size_column_migration_name}.rb", "db/migrate/#{migration_time}_#{size_column_migration_name}.rb" + } + + prompt_if_exists for_file: context_column_migration_name, to_execute: ->{ + copy_file "#{context_column_migration_name}.rb", "db/migrate/#{migration_time}_#{context_column_migration_name}.rb" + } end private @@ -17,5 +25,12 @@ def migration_time Time.now.strftime("%Y%m%d%H%M%S") end + def size_column_migration_name + 'add_size_to_s3_multipart_uploads' + end + + def context_column_migration_name + 'add_context_to_s3_multipart_uploads' + end end end diff --git a/lib/generators/s3_multipart/migration_existence_validation_helper.rb b/lib/generators/s3_multipart/migration_existence_validation_helper.rb new file mode 100644 index 0000000..2cd7b0b --- /dev/null +++ b/lib/generators/s3_multipart/migration_existence_validation_helper.rb @@ -0,0 +1,29 @@ +module MigrationExistenceValidationHelper + attr_reader :migration_name + + def prompt_if_exists(for_file:, to_execute:) + @migration_name = for_file + + if matching_migrations.length > 0 + say_status('conflict', matching_migrations.join(', '), :red) + to_execute.call if agree_to_create_file + else + to_execute.call + end + end + + private + + def agree_to_create_file + yes? "#{matching_migrations.length > 1 ? 'Migrations exist' : 'Migration exists'}, "\ + "creating a new migration may cause a migration error. Do you want to create the file? (y/n)" + end + + def migration_file_path + "db/migrate/*_#{migration_name}.rb" + end + + def matching_migrations + Dir[migration_file_path] + end +end diff --git a/lib/generators/s3_multipart/uploader_generator.rb b/lib/generators/s3_multipart/uploader_generator.rb index 7814796..1f91b59 100644 --- a/lib/generators/s3_multipart/uploader_generator.rb +++ b/lib/generators/s3_multipart/uploader_generator.rb @@ -1,7 +1,10 @@ +require_relative 'migration_existence_validation_helper.rb' require 'rails/generators' module S3Multipart class UploaderGenerator < Rails::Generators::Base + include MigrationExistenceValidationHelper + desc "Generates an uploader for use with the S3 Multipart gem" source_root File.expand_path("../templates", __FILE__) @@ -16,11 +19,17 @@ def create_uploader def create_migrations # return unless options.migrations? - template "add_uploader_column_to_model.rb", "db/migrate/#{migration_time}_add_uploader_to_#{model}.rb" + prompt_if_exists for_file: migration_name, to_execute: ->{ + template "add_uploader_column_to_model.rb", "db/migrate/#{migration_time}_#{migration_name}.rb" + } end private + def migration_name + "add_uploader_to_#{model}" + end + def migration_time Time.now.strftime("%Y%m%d%H%M%S") end @@ -30,4 +39,4 @@ def model_constant end end -end \ No newline at end of file +end diff --git a/s3_multipart.gemspec b/s3_multipart.gemspec index c95d4b6..dd960c4 100644 --- a/s3_multipart.gemspec +++ b/s3_multipart.gemspec @@ -25,5 +25,6 @@ Gem::Specification.new do |s| s.add_development_dependency "rails" s.add_development_dependency "sqlite3" s.add_development_dependency 'rspec-rails', '~> 2.14', '>= 2.14.2' + s.add_development_dependency 'generator_spec' s.add_development_dependency 'capybara' end diff --git a/spec/generators/install_generator_spec.rb b/spec/generators/install_generator_spec.rb new file mode 100644 index 0000000..f3e3ab7 --- /dev/null +++ b/spec/generators/install_generator_spec.rb @@ -0,0 +1,25 @@ +require 'spec_helper.rb' +require_relative '../../lib/generators/s3_multipart/install_generator.rb' + +describe S3Multipart::InstallGenerator, type: :generator do + destination File.expand_path('../../../tmp', __FILE__) + + before(:all) do + prepare_destination + mkdir "#{destination_root}/config" + touch "#{destination_root}/config/routes.rb" + run_generator + end + + it 'creates a migration for an S3 uploads table' do + assert_migration "#{destination_root}/db/migrate/create_s3_multipart_uploads.rb" + end + + it 'creates an AWS credential YAML configuration file' do + assert_file 'config/aws.yml' + end + + it 'mounts the gem engine in the app routes' do + expect(run_generator).to match 'mount S3Multipart::Engine => "/s3_multipart"' + end +end diff --git a/spec/generators/install_new_migrations_generator_spec.rb b/spec/generators/install_new_migrations_generator_spec.rb new file mode 100644 index 0000000..d911acc --- /dev/null +++ b/spec/generators/install_new_migrations_generator_spec.rb @@ -0,0 +1,21 @@ +require 'spec_helper.rb' +require_relative '../../lib/generators/s3_multipart/install_new_migrations_generator.rb' + +describe S3Multipart::InstallNewMigrationsGenerator, type: :generator do + destination File.expand_path('../../../tmp', __FILE__) + + before(:all) do + prepare_destination + run_generator + end + + it 'creates a migration to add a size column to the S3 uploads table' do + migration_exists = !!Dir["#{destination_root}/db/migrate/*_add_size_to_s3_multipart_uploads.rb"].length + expect(migration_exists).to be_true + end + + it 'creates a migration to add a context column to the S3 uploads table' do + migration_exists = !!Dir["#{destination_root}/db/migrate/*_add_context_to_s3_multipart_uploads.rb"].length + expect(migration_exists).to be_true + end +end diff --git a/spec/generators/uploader_generator_spec.rb b/spec/generators/uploader_generator_spec.rb new file mode 100644 index 0000000..ba45680 --- /dev/null +++ b/spec/generators/uploader_generator_spec.rb @@ -0,0 +1,29 @@ +require 'spec_helper.rb' +require_relative '../../lib/generators/s3_multipart/uploader_generator.rb' + +describe S3Multipart::UploaderGenerator, type: :generator do + destination File.expand_path('../../../tmp', __FILE__) + arguments %w(foo) + + before(:all) do + prepare_destination + mkdir "#{destination_root}/app" + run_generator + end + + it 'creates a migration to add an uploader column to the specified model table' do + assert_migration "#{destination_root}/db/migrate/add_uploader_to_foo.rb" + end + + it 'creates an uploaders folder' do + assert_directory "#{destination_root}/app/uploaders" + end + + it 'creates a multipart folder in the uploaders folder' do + assert_directory "#{destination_root}/app/uploaders/multipart" + end + + it 'adds an uploader for the specified model in the uploaders multipart folder' do + assert_file "#{destination_root}/app/uploaders/multipart/foo_uploader.rb" + end +end diff --git a/spec/spec_helper.rb b/spec/spec_helper.rb index 461412a..e1cc67e 100644 --- a/spec/spec_helper.rb +++ b/spec/spec_helper.rb @@ -10,9 +10,34 @@ require 'rspec/rails' require 'capybara/rails' -# Engine config initializer -require 'setup_credentials.rb' +require 'generator_spec' RSpec.configure do |config| #config.use_transactional_fixtures = true -end \ No newline at end of file +end + +class S3Response + class << self + def success + response_body( + %{<PostResponse> + <Key>2f020fj20fj</Key> + <UploadId>fj2foj20f22</UploadId> + </PostResponse>} + ) + end + + def upload_not_found + response_body( + %{<PostResponse> + <Message>The specified upload does not exist. The upload ID may be invalid, or the upload may have been aborted or completed.</Message> + </PostResponse>} + ) + end + + def response_body(body) + OpenStruct.new({ body: body }) + end + end + private_class_method :response_body +end diff --git a/spec/unit/upload_spec.rb b/spec/unit/upload_spec.rb index 132c58b..0076891 100644 --- a/spec/unit/upload_spec.rb +++ b/spec/unit/upload_spec.rb @@ -1,10 +1,20 @@ require 'spec_helper.rb' +def s3_response +end + describe "An upload object" do before(:all) do + S3Multipart.configure do |config| + config.bucket_name = '' + config.s3_access_key = '' + config.s3_secret_key = '' + config.revision = S3Multipart::VERSION + end class Upload include S3Multipart::TransferHelpers end + S3Multipart::Http.stub(post: S3Response.success) @upload = Upload.new end @@ -21,7 +31,7 @@ class Upload it "should sign many parts" do response = @upload.sign_batch( object_name: "example_object", content_lengths: "1000000-1000000-1000000", - upload_id: "a83jrhfs94jcj3c3" ) + upload_id: "a83jrhfs94jcj3c3" ) response.should be_an_instance_of(Array) response.first[:authorization].should match(/AWS/) @@ -30,18 +40,20 @@ class Upload it "should sign a single part" do response = @upload.sign_part( object_name: "example_object", content_length: "1000000", - upload_id: "a83jrhfs94jcj3c3" ) + upload_id: "a83jrhfs94jcj3c3" ) response.should be_an_instance_of(Hash) response[:authorization].should match(/AWS/) end it "should unsuccessfully attempt to complete an upload that doesn't exist" do + S3Multipart::Http.stub(post: S3Response.upload_not_found) + response = @upload.complete( object_name: "example_object", content_length: "1000000", parts: [{partNum: 1, ETag: "jf93nda3Sf8FSh"}], content_type: "application/xml", - upload_id: "a83jrhfs94jcj3c3" ) + upload_id: "a83jrhfs94jcj3c3" ) response[:error].should eql("Upload does not exist") end