vagrant-unbundled 1.9.7.1 → 1.9.8.1

Sign up to get free protection for your applications and to get access to all the features.
Files changed (280) hide show
  1. checksums.yaml +4 -4
  2. data/CHANGELOG.md +36 -0
  3. data/Gemfile.lock +10 -6
  4. data/contrib/bash/completion.sh +1 -1
  5. data/contrib/sudoers/linux-ubuntu +3 -4
  6. data/lib/vagrant/errors.rb +8 -0
  7. data/lib/vagrant/machine.rb +2 -0
  8. data/lib/vagrant/util/platform.rb +1 -1
  9. data/lib/vagrant/util/powershell.rb +42 -13
  10. data/lib/vagrant/util/safe_exec.rb +13 -2
  11. data/lib/vagrant/util/ssh.rb +11 -1
  12. data/plugins/commands/box/command/update.rb +12 -7
  13. data/plugins/commands/login/client.rb +15 -6
  14. data/plugins/commands/login/command.rb +13 -3
  15. data/plugins/commands/up/command.rb +9 -0
  16. data/plugins/commands/validate/command.rb +4 -4
  17. data/plugins/guests/darwin/cap/shell_expand_guest_path.rb +2 -2
  18. data/plugins/guests/freebsd/cap/configure_networks.rb +1 -1
  19. data/plugins/guests/freebsd/cap/shell_expand_guest_path.rb +2 -2
  20. data/plugins/guests/linux/cap/shell_expand_guest_path.rb +2 -2
  21. data/plugins/guests/netbsd/cap/shell_expand_guest_path.rb +2 -2
  22. data/plugins/guests/openbsd/cap/shell_expand_guest_path.rb +2 -2
  23. data/plugins/guests/windows/cap/public_key.rb +21 -45
  24. data/plugins/kernel_v2/config/ssh_connect.rb +3 -0
  25. data/plugins/providers/docker/config.rb +4 -0
  26. data/plugins/providers/docker/driver/compose.rb +11 -4
  27. data/plugins/providers/hyperv/action/wait_for_ip_address.rb +15 -11
  28. data/plugins/providers/hyperv/scripts/get_network_config.ps1 +24 -9
  29. data/plugins/providers/virtualbox/action/prepare_nfs_settings.rb +18 -0
  30. data/plugins/provisioners/ansible/provisioner/host.rb +1 -1
  31. data/plugins/provisioners/chef/cap/debian/chef_install.rb +2 -2
  32. data/plugins/provisioners/chef/cap/freebsd/chef_install.rb +2 -2
  33. data/plugins/provisioners/chef/cap/omnios/chef_install.rb +2 -2
  34. data/plugins/provisioners/chef/cap/redhat/chef_install.rb +2 -2
  35. data/plugins/provisioners/chef/cap/suse/chef_install.rb +2 -2
  36. data/plugins/provisioners/chef/cap/windows/chef_install.rb +2 -2
  37. data/plugins/provisioners/chef/config/base.rb +17 -0
  38. data/plugins/provisioners/chef/config/chef_zero.rb +7 -0
  39. data/plugins/provisioners/chef/installer.rb +8 -7
  40. data/plugins/provisioners/chef/omnibus.rb +4 -6
  41. data/plugins/provisioners/chef/provisioner/base.rb +1 -0
  42. data/plugins/provisioners/chef/provisioner/chef_solo.rb +2 -1
  43. data/plugins/provisioners/file/provisioner.rb +18 -2
  44. data/plugins/provisioners/puppet/provisioner/puppet.rb +0 -2
  45. data/plugins/provisioners/salt/bootstrap-salt.sh +9 -5
  46. data/plugins/provisioners/shell/provisioner.rb +1 -1
  47. data/plugins/synced_folders/rsync/command/rsync_auto.rb +6 -1
  48. data/plugins/synced_folders/rsync/helper.rb +10 -0
  49. data/templates/locales/en.yml +27 -1
  50. data/templates/locales/providers_docker.yml +2 -0
  51. data/test/unit/base.rb +1 -3
  52. data/test/unit/plugins/commands/box/command/add_test.rb +3 -3
  53. data/test/unit/plugins/commands/box/command/remove_test.rb +6 -6
  54. data/test/unit/plugins/commands/box/command/repackage_test.rb +2 -4
  55. data/test/unit/plugins/commands/box/command/update_test.rb +36 -14
  56. data/test/unit/plugins/commands/init/command_test.rb +1 -1
  57. data/test/unit/plugins/commands/list-commands/command_test.rb +2 -2
  58. data/test/unit/plugins/commands/login/client_test.rb +5 -1
  59. data/test/unit/plugins/commands/package/command_test.rb +1 -1
  60. data/test/unit/plugins/commands/plugin/action/expunge_plugins_test.rb +1 -1
  61. data/test/unit/plugins/commands/plugin/action/install_gem_test.rb +3 -3
  62. data/test/unit/plugins/commands/plugin/action/plugin_exists_check_test.rb +3 -3
  63. data/test/unit/plugins/commands/plugin/action/uninstall_plugin_test.rb +1 -1
  64. data/test/unit/plugins/commands/plugin/action/update_gems_test.rb +2 -2
  65. data/test/unit/plugins/commands/port/command_test.rb +3 -3
  66. data/test/unit/plugins/commands/push/command_test.rb +1 -1
  67. data/test/unit/plugins/commands/snapshot/command/list_test.rb +2 -3
  68. data/test/unit/plugins/commands/ssh_config/command_test.rb +1 -1
  69. data/test/unit/plugins/commands/up/command_test.rb +69 -2
  70. data/test/unit/plugins/commands/validate/command_test.rb +47 -1
  71. data/test/unit/plugins/communicators/ssh/communicator_test.rb +5 -5
  72. data/test/unit/plugins/communicators/winrm/communicator_test.rb +6 -6
  73. data/test/unit/plugins/communicators/winrm/helper_test.rb +24 -23
  74. data/test/unit/plugins/communicators/winssh/communicator_test.rb +5 -5
  75. data/test/unit/plugins/guests/darwin/cap/shell_expand_guest_path_test.rb +43 -0
  76. data/test/unit/plugins/guests/freebsd/cap/configure_networks_test.rb +1 -1
  77. data/test/unit/plugins/guests/freebsd/cap/shell_expand_guest_path_test.rb +44 -0
  78. data/test/unit/plugins/guests/linux/cap/shell_expand_guest_path_test.rb +43 -0
  79. data/test/unit/plugins/guests/netbsd/cap/shell_expand_guest_path_test.rb +43 -0
  80. data/test/unit/plugins/guests/omnios/cap/mount_nfs_folder_test.rb +1 -3
  81. data/test/unit/plugins/guests/openbsd/cap/shell_expand_guest_path_test.rb +43 -0
  82. data/test/unit/plugins/guests/smartos/cap/change_host_name_test.rb +2 -2
  83. data/test/unit/plugins/guests/smartos/cap/configure_networks_test.rb +2 -2
  84. data/test/unit/plugins/guests/smartos/cap/halt_test.rb +2 -2
  85. data/test/unit/plugins/guests/smartos/cap/insert_public_key_test.rb +1 -1
  86. data/test/unit/plugins/guests/smartos/cap/mount_nfs_test.rb +2 -2
  87. data/test/unit/plugins/guests/smartos/cap/rsync_test.rb +2 -2
  88. data/test/unit/plugins/guests/windows/cap/insert_public_key_test.rb +2 -2
  89. data/test/unit/plugins/guests/windows/cap/remove_public_key_test.rb +4 -3
  90. data/test/unit/plugins/guests/windows/config_test.rb +1 -1
  91. data/test/unit/plugins/guests/windows/guest_network_test.rb +2 -2
  92. data/test/unit/plugins/hosts/linux/cap/nfs_test.rb +2 -0
  93. data/test/unit/plugins/kernel_v2/config/push_test.rb +1 -1
  94. data/test/unit/plugins/kernel_v2/config/vm_test.rb +7 -7
  95. data/test/unit/plugins/providers/docker/action/create_test.rb +1 -1
  96. data/test/unit/plugins/providers/docker/command/exec_test.rb +1 -1
  97. data/test/unit/plugins/providers/docker/config_test.rb +23 -4
  98. data/test/unit/plugins/providers/docker/driver_compose_test.rb +60 -30
  99. data/test/unit/plugins/providers/docker/driver_test.rb +31 -31
  100. data/test/unit/plugins/providers/docker/synced_folder_test.rb +3 -3
  101. data/test/unit/plugins/providers/hyperv/provider_test.rb +19 -19
  102. data/test/unit/plugins/providers/virtualbox/action/network_fix_ipv6_test.rb +2 -2
  103. data/test/unit/plugins/providers/virtualbox/action/network_test.rb +1 -1
  104. data/test/unit/plugins/providers/virtualbox/action/prepare_nfs_settings_test.rb +34 -8
  105. data/test/unit/plugins/providers/virtualbox/action/prepare_nfs_valid_ids_test.rb +3 -3
  106. data/test/unit/plugins/providers/virtualbox/cap_test.rb +2 -2
  107. data/test/unit/plugins/providers/virtualbox/config_test.rb +6 -6
  108. data/test/unit/plugins/providers/virtualbox/synced_folder_test.rb +6 -8
  109. data/test/unit/plugins/provisioners/ansible/config/guest_test.rb +1 -1
  110. data/test/unit/plugins/provisioners/ansible/config/host_test.rb +4 -4
  111. data/test/unit/plugins/provisioners/ansible/config/shared.rb +2 -2
  112. data/test/unit/plugins/provisioners/ansible/provisioner_test.rb +165 -157
  113. data/test/unit/plugins/provisioners/chef/command_builder_test.rb +2 -2
  114. data/test/unit/plugins/provisioners/chef/config/base_test.rb +13 -0
  115. data/test/unit/plugins/provisioners/chef/config/chef_zero_test.rb +11 -0
  116. data/test/unit/plugins/provisioners/chef/omnibus_test.rb +17 -7
  117. data/test/unit/plugins/provisioners/docker/config_test.rb +2 -1
  118. data/test/unit/plugins/provisioners/docker/provisioner_test.rb +13 -13
  119. data/test/unit/plugins/provisioners/file/provisioner_test.rb +32 -14
  120. data/test/unit/plugins/provisioners/puppet/provisioner/puppet_test.rb +51 -0
  121. data/test/unit/plugins/provisioners/salt/provisioner_test.rb +5 -5
  122. data/test/unit/plugins/provisioners/shell/provisioner_test.rb +35 -4
  123. data/test/unit/plugins/pushes/ftp/adapter_test.rb +1 -0
  124. data/test/unit/plugins/synced_folders/nfs/action_cleanup_test.rb +1 -1
  125. data/test/unit/plugins/synced_folders/nfs/config_test.rb +1 -1
  126. data/test/unit/plugins/synced_folders/rsync/command/rsync_auto_test.rb +44 -12
  127. data/test/unit/plugins/synced_folders/rsync/command/rsync_test.rb +5 -5
  128. data/test/unit/plugins/synced_folders/rsync/helper_test.rb +47 -29
  129. data/test/unit/plugins/synced_folders/rsync/synced_folder_test.rb +5 -5
  130. data/test/unit/vagrant/action/builtin/box_add_test.rb +27 -27
  131. data/test/unit/vagrant/action/builtin/box_check_outdated_test.rb +10 -10
  132. data/test/unit/vagrant/action/builtin/box_remove_test.rb +15 -15
  133. data/test/unit/vagrant/action/builtin/confirm_test.rb +1 -1
  134. data/test/unit/vagrant/action/builtin/graceful_halt_test.rb +2 -2
  135. data/test/unit/vagrant/action/builtin/handle_box_test.rb +8 -8
  136. data/test/unit/vagrant/action/builtin/handle_forwarded_port_collisions_test.rb +1 -1
  137. data/test/unit/vagrant/action/builtin/is_env_set_test.rb +2 -2
  138. data/test/unit/vagrant/action/builtin/is_state_test.rb +6 -6
  139. data/test/unit/vagrant/action/builtin/mixin_synced_folders_test.rb +6 -6
  140. data/test/unit/vagrant/action/builtin/provision_test.rb +1 -1
  141. data/test/unit/vagrant/action/builtin/provisioner_cleanup_test.rb +1 -1
  142. data/test/unit/vagrant/action/builtin/synced_folder_cleanup_test.rb +6 -6
  143. data/test/unit/vagrant/action/builtin/synced_folders_test.rb +3 -3
  144. data/test/unit/vagrant/batch_action_test.rb +2 -2
  145. data/test/unit/vagrant/box_collection_test.rb +1 -1
  146. data/test/unit/vagrant/box_test.rb +6 -6
  147. data/test/unit/vagrant/capability_host_test.rb +3 -3
  148. data/test/unit/vagrant/cli_test.rb +3 -3
  149. data/test/unit/vagrant/environment_test.rb +21 -20
  150. data/test/unit/vagrant/guest_test.rb +7 -7
  151. data/test/unit/vagrant/machine_index_test.rb +4 -4
  152. data/test/unit/vagrant/machine_test.rb +28 -17
  153. data/test/unit/vagrant/plugin/manager_test.rb +12 -12
  154. data/test/unit/vagrant/plugin/state_file_test.rb +2 -2
  155. data/test/unit/vagrant/plugin/v1/command_test.rb +9 -8
  156. data/test/unit/vagrant/plugin/v2/command_test.rb +54 -43
  157. data/test/unit/vagrant/plugin/v2/plugin_test.rb +4 -3
  158. data/test/unit/vagrant/plugin/v2/provider_test.rb +3 -3
  159. data/test/unit/vagrant/shared_helpers_test.rb +6 -6
  160. data/test/unit/vagrant/ui_test.rb +21 -21
  161. data/test/unit/vagrant/util/downloader_test.rb +7 -7
  162. data/test/unit/vagrant/util/ssh_test.rb +41 -5
  163. data/test/unit/vagrant/util/subprocess_test.rb +7 -7
  164. data/test/unit/vagrant_test.rb +9 -9
  165. data/vagrant.gemspec +3 -2
  166. data/vendor/bundle/ruby/2.4.0/bundler/gems/vagrant-spec-af86757912f7/vagrant-spec.gemspec +1 -1
  167. data/vendor/bundle/ruby/2.4.0/gems/fake_ftp-0.1.1/.gitignore +7 -0
  168. data/vendor/bundle/ruby/2.4.0/gems/fake_ftp-0.1.1/.rspec +2 -0
  169. data/vendor/bundle/ruby/2.4.0/gems/fake_ftp-0.1.1/.travis.yml +5 -0
  170. data/vendor/bundle/ruby/2.4.0/gems/fake_ftp-0.1.1/CONTRIBUTORS.md +19 -0
  171. data/vendor/bundle/ruby/2.4.0/gems/fake_ftp-0.1.1/Gemfile +12 -0
  172. data/vendor/bundle/ruby/2.4.0/gems/fake_ftp-0.1.1/Gemfile.lock +44 -0
  173. data/vendor/bundle/ruby/2.4.0/gems/fake_ftp-0.1.1/Guardfile +10 -0
  174. data/vendor/bundle/ruby/2.4.0/gems/fake_ftp-0.1.1/README.md +134 -0
  175. data/vendor/bundle/ruby/2.4.0/gems/fake_ftp-0.1.1/Rakefile +10 -0
  176. data/vendor/bundle/ruby/2.4.0/gems/fake_ftp-0.1.1/fake_ftp.gemspec +22 -0
  177. data/vendor/bundle/ruby/2.4.0/gems/fake_ftp-0.1.1/lib/fake_ftp.rb +5 -0
  178. data/vendor/bundle/ruby/2.4.0/gems/fake_ftp-0.1.1/lib/fake_ftp/file.rb +34 -0
  179. data/vendor/bundle/ruby/2.4.0/gems/fake_ftp-0.1.1/lib/fake_ftp/server.rb +340 -0
  180. data/vendor/bundle/ruby/2.4.0/gems/fake_ftp-0.1.1/lib/fake_ftp/version.rb +3 -0
  181. data/vendor/bundle/ruby/2.4.0/gems/fake_ftp-0.1.1/spec/fixtures/invisible_bike.jpg +0 -0
  182. data/vendor/bundle/ruby/2.4.0/gems/fake_ftp-0.1.1/spec/fixtures/text_file.txt +1 -0
  183. data/vendor/bundle/ruby/2.4.0/gems/fake_ftp-0.1.1/spec/functional/server_spec.rb +468 -0
  184. data/vendor/bundle/ruby/2.4.0/gems/fake_ftp-0.1.1/spec/integration/server_spec.rb +81 -0
  185. data/vendor/bundle/ruby/2.4.0/gems/fake_ftp-0.1.1/spec/models/fake_ftp/file_spec.rb +102 -0
  186. data/vendor/bundle/ruby/2.4.0/gems/fake_ftp-0.1.1/spec/models/fake_ftp/server_spec.rb +76 -0
  187. data/vendor/bundle/ruby/2.4.0/gems/fake_ftp-0.1.1/spec/spec_helper.rb +18 -0
  188. data/vendor/bundle/ruby/2.4.0/gems/rake-12.0.0/.gitignore +14 -0
  189. data/vendor/bundle/ruby/2.4.0/gems/rake-12.0.0/.rubocop.yml +57 -0
  190. data/vendor/bundle/ruby/2.4.0/gems/rake-12.0.0/.travis.yml +21 -0
  191. data/vendor/bundle/ruby/2.4.0/gems/rake-12.0.0/CONTRIBUTING.rdoc +36 -0
  192. data/vendor/bundle/ruby/2.4.0/gems/rake-12.0.0/Gemfile +3 -0
  193. data/vendor/bundle/ruby/2.4.0/gems/rake-12.0.0/History.rdoc +2247 -0
  194. data/vendor/bundle/ruby/2.4.0/gems/rake-12.0.0/MIT-LICENSE +21 -0
  195. data/vendor/bundle/ruby/2.4.0/gems/rake-12.0.0/README.rdoc +156 -0
  196. data/vendor/bundle/ruby/2.4.0/gems/rake-12.0.0/Rakefile +38 -0
  197. data/vendor/bundle/ruby/2.4.0/gems/rake-12.0.0/appveyor.yml +21 -0
  198. data/vendor/bundle/ruby/2.4.0/gems/rake-12.0.0/bin/console +7 -0
  199. data/vendor/bundle/ruby/2.4.0/gems/rake-12.0.0/bin/setup +6 -0
  200. data/vendor/bundle/ruby/2.4.0/gems/rake-12.0.0/doc/command_line_usage.rdoc +158 -0
  201. data/vendor/bundle/ruby/2.4.0/gems/rake-12.0.0/doc/example/Rakefile1 +38 -0
  202. data/vendor/bundle/ruby/2.4.0/gems/rake-12.0.0/doc/example/Rakefile2 +35 -0
  203. data/vendor/bundle/ruby/2.4.0/gems/rake-12.0.0/doc/example/a.c +6 -0
  204. data/vendor/bundle/ruby/2.4.0/gems/rake-12.0.0/doc/example/b.c +6 -0
  205. data/vendor/bundle/ruby/2.4.0/gems/rake-12.0.0/doc/example/main.c +11 -0
  206. data/vendor/bundle/ruby/2.4.0/gems/rake-12.0.0/doc/glossary.rdoc +42 -0
  207. data/vendor/bundle/ruby/2.4.0/gems/rake-12.0.0/doc/jamis.rb +591 -0
  208. data/vendor/bundle/ruby/2.4.0/gems/rake-12.0.0/doc/proto_rake.rdoc +127 -0
  209. data/vendor/bundle/ruby/2.4.0/gems/rake-12.0.0/doc/rake.1 +156 -0
  210. data/vendor/bundle/ruby/2.4.0/gems/rake-12.0.0/doc/rakefile.rdoc +622 -0
  211. data/vendor/bundle/ruby/2.4.0/gems/rake-12.0.0/doc/rational.rdoc +151 -0
  212. data/vendor/bundle/ruby/2.4.0/gems/rake-12.0.0/exe/rake +27 -0
  213. data/vendor/bundle/ruby/2.4.0/gems/rake-12.0.0/lib/rake.rb +70 -0
  214. data/vendor/bundle/ruby/2.4.0/gems/rake-12.0.0/lib/rake/application.rb +785 -0
  215. data/vendor/bundle/ruby/2.4.0/gems/rake-12.0.0/lib/rake/backtrace.rb +23 -0
  216. data/vendor/bundle/ruby/2.4.0/gems/rake-12.0.0/lib/rake/clean.rb +77 -0
  217. data/vendor/bundle/ruby/2.4.0/gems/rake-12.0.0/lib/rake/cloneable.rb +16 -0
  218. data/vendor/bundle/ruby/2.4.0/gems/rake-12.0.0/lib/rake/cpu_counter.rb +106 -0
  219. data/vendor/bundle/ruby/2.4.0/gems/rake-12.0.0/lib/rake/default_loader.rb +14 -0
  220. data/vendor/bundle/ruby/2.4.0/gems/rake-12.0.0/lib/rake/dsl_definition.rb +194 -0
  221. data/vendor/bundle/ruby/2.4.0/gems/rake-12.0.0/lib/rake/early_time.rb +21 -0
  222. data/vendor/bundle/ruby/2.4.0/gems/rake-12.0.0/lib/rake/ext/core.rb +25 -0
  223. data/vendor/bundle/ruby/2.4.0/gems/rake-12.0.0/lib/rake/ext/string.rb +175 -0
  224. data/vendor/bundle/ruby/2.4.0/gems/rake-12.0.0/lib/rake/file_creation_task.rb +24 -0
  225. data/vendor/bundle/ruby/2.4.0/gems/rake-12.0.0/lib/rake/file_list.rb +434 -0
  226. data/vendor/bundle/ruby/2.4.0/gems/rake-12.0.0/lib/rake/file_task.rb +46 -0
  227. data/vendor/bundle/ruby/2.4.0/gems/rake-12.0.0/lib/rake/file_utils.rb +136 -0
  228. data/vendor/bundle/ruby/2.4.0/gems/rake-12.0.0/lib/rake/file_utils_ext.rb +144 -0
  229. data/vendor/bundle/ruby/2.4.0/gems/rake-12.0.0/lib/rake/invocation_chain.rb +56 -0
  230. data/vendor/bundle/ruby/2.4.0/gems/rake-12.0.0/lib/rake/invocation_exception_mixin.rb +16 -0
  231. data/vendor/bundle/ruby/2.4.0/gems/rake-12.0.0/lib/rake/late_time.rb +17 -0
  232. data/vendor/bundle/ruby/2.4.0/gems/rake-12.0.0/lib/rake/linked_list.rb +111 -0
  233. data/vendor/bundle/ruby/2.4.0/gems/rake-12.0.0/lib/rake/loaders/makefile.rb +53 -0
  234. data/vendor/bundle/ruby/2.4.0/gems/rake-12.0.0/lib/rake/multi_task.rb +49 -0
  235. data/vendor/bundle/ruby/2.4.0/gems/rake-12.0.0/lib/rake/name_space.rb +37 -0
  236. data/vendor/bundle/ruby/2.4.0/gems/rake-12.0.0/lib/rake/packagetask.rb +210 -0
  237. data/vendor/bundle/ruby/2.4.0/gems/rake-12.0.0/lib/rake/phony.rb +15 -0
  238. data/vendor/bundle/ruby/2.4.0/gems/rake-12.0.0/lib/rake/private_reader.rb +20 -0
  239. data/vendor/bundle/ruby/2.4.0/gems/rake-12.0.0/lib/rake/promise.rb +99 -0
  240. data/vendor/bundle/ruby/2.4.0/gems/rake-12.0.0/lib/rake/pseudo_status.rb +29 -0
  241. data/vendor/bundle/ruby/2.4.0/gems/rake-12.0.0/lib/rake/rake_module.rb +38 -0
  242. data/vendor/bundle/ruby/2.4.0/gems/rake-12.0.0/lib/rake/rake_test_loader.rb +21 -0
  243. data/vendor/bundle/ruby/2.4.0/gems/rake-12.0.0/lib/rake/rule_recursion_overflow_error.rb +19 -0
  244. data/vendor/bundle/ruby/2.4.0/gems/rake-12.0.0/lib/rake/scope.rb +42 -0
  245. data/vendor/bundle/ruby/2.4.0/gems/rake-12.0.0/lib/rake/task.rb +390 -0
  246. data/vendor/bundle/ruby/2.4.0/gems/rake-12.0.0/lib/rake/task_argument_error.rb +7 -0
  247. data/vendor/bundle/ruby/2.4.0/gems/rake-12.0.0/lib/rake/task_arguments.rb +108 -0
  248. data/vendor/bundle/ruby/2.4.0/gems/rake-12.0.0/lib/rake/task_manager.rb +303 -0
  249. data/vendor/bundle/ruby/2.4.0/gems/rake-12.0.0/lib/rake/tasklib.rb +11 -0
  250. data/vendor/bundle/ruby/2.4.0/gems/rake-12.0.0/lib/rake/testtask.rb +222 -0
  251. data/vendor/bundle/ruby/2.4.0/gems/rake-12.0.0/lib/rake/thread_history_display.rb +48 -0
  252. data/vendor/bundle/ruby/2.4.0/gems/rake-12.0.0/lib/rake/thread_pool.rb +162 -0
  253. data/vendor/bundle/ruby/2.4.0/gems/rake-12.0.0/lib/rake/trace_output.rb +22 -0
  254. data/vendor/bundle/ruby/2.4.0/gems/rake-12.0.0/lib/rake/version.rb +9 -0
  255. data/vendor/bundle/ruby/2.4.0/gems/rake-12.0.0/lib/rake/win32.rb +50 -0
  256. data/vendor/bundle/ruby/2.4.0/gems/rake-12.0.0/rake.gemspec +39 -0
  257. data/vendor/bundle/ruby/2.4.0/gems/rspec-its-1.2.0/.gitignore +19 -0
  258. data/vendor/bundle/ruby/2.4.0/gems/rspec-its-1.2.0/.rspec +3 -0
  259. data/vendor/bundle/ruby/2.4.0/gems/rspec-its-1.2.0/.travis.yml +24 -0
  260. data/vendor/bundle/ruby/2.4.0/gems/rspec-its-1.2.0/Changelog.md +49 -0
  261. data/vendor/bundle/ruby/2.4.0/gems/rspec-its-1.2.0/Gemfile +26 -0
  262. data/vendor/bundle/ruby/2.4.0/gems/rspec-its-1.2.0/LICENSE.txt +27 -0
  263. data/vendor/bundle/ruby/2.4.0/gems/rspec-its-1.2.0/README.md +72 -0
  264. data/vendor/bundle/ruby/2.4.0/gems/rspec-its-1.2.0/Rakefile +16 -0
  265. data/vendor/bundle/ruby/2.4.0/gems/rspec-its-1.2.0/cucumber.yml +2 -0
  266. data/vendor/bundle/ruby/2.4.0/gems/rspec-its-1.2.0/features/its.feature +125 -0
  267. data/vendor/bundle/ruby/2.4.0/gems/rspec-its-1.2.0/features/step_definitions/additional_cli_steps.rb +21 -0
  268. data/vendor/bundle/ruby/2.4.0/gems/rspec-its-1.2.0/features/support/env.rb +23 -0
  269. data/vendor/bundle/ruby/2.4.0/gems/rspec-its-1.2.0/lib/rspec/its.rb +149 -0
  270. data/vendor/bundle/ruby/2.4.0/gems/rspec-its-1.2.0/lib/rspec/its/version.rb +5 -0
  271. data/vendor/bundle/ruby/2.4.0/gems/rspec-its-1.2.0/rspec-its.gemspec +28 -0
  272. data/vendor/bundle/ruby/2.4.0/gems/rspec-its-1.2.0/script/test_all +20 -0
  273. data/vendor/bundle/ruby/2.4.0/gems/rspec-its-1.2.0/spec/rspec/its_spec.rb +237 -0
  274. data/vendor/bundle/ruby/2.4.0/gems/rspec-its-1.2.0/spec/spec_helper.rb +15 -0
  275. data/vendor/bundle/ruby/2.4.0/specifications/fake_ftp-0.1.1.gemspec +20 -0
  276. data/vendor/bundle/ruby/2.4.0/specifications/rake-12.0.0.gemspec +43 -0
  277. data/vendor/bundle/ruby/2.4.0/specifications/rspec-its-1.2.0.gemspec +47 -0
  278. data/version.txt +1 -1
  279. metadata +137 -7
  280. data/2.14.0 +0 -5
@@ -0,0 +1,10 @@
1
+ require 'bundler'
2
+ Bundler::GemHelper.install_tasks
3
+
4
+ require 'rspec/core'
5
+ require 'rspec/core/rake_task'
6
+
7
+ RSpec::Core::RakeTask.new('spec')
8
+
9
+ # If you want to make this the default task
10
+ task :default => :spec
@@ -0,0 +1,22 @@
1
+ # -*- encoding: utf-8 -*-
2
+ $:.push File.expand_path("../lib", __FILE__)
3
+ require "fake_ftp/version"
4
+
5
+ Gem::Specification.new do |s|
6
+ s.name = "fake_ftp"
7
+ s.version = FakeFtp::VERSION
8
+ s.platform = Gem::Platform::RUBY
9
+ s.authors = ["Colin Shield", "Eric Saxby"]
10
+ s.email = ["sax+github@livinginthepast.org"]
11
+ s.homepage = "http://rubygems.org/gems/fake_ftp"
12
+ s.summary = %q{Creates a fake FTP server for use in testing}
13
+ s.description = %q{Testing FTP? Use this!}
14
+ s.license = 'MIT'
15
+
16
+ s.required_rubygems_version = ">= 1.3.6"
17
+
18
+ s.files = `git ls-files`.split("\n")
19
+ s.test_files = `git ls-files -- {test,spec,features}/*`.split("\n")
20
+ s.executables = `git ls-files -- bin/*`.split("\n").map{ |f| File.basename(f) }
21
+ s.require_paths = ["lib"]
22
+ end
@@ -0,0 +1,5 @@
1
+ require 'fake_ftp/server'
2
+ require 'fake_ftp/file'
3
+
4
+ module FakeFtp
5
+ end
@@ -0,0 +1,34 @@
1
+ module FakeFtp
2
+ class File
3
+ attr_accessor :bytes, :name, :last_modified_time
4
+ attr_writer :type
5
+ attr_accessor :data
6
+ attr_reader :created
7
+
8
+ def initialize(name = nil, data = nil, type = nil, last_modified_time = Time.now)
9
+ @created = Time.now
10
+ @name = name
11
+ @data = data
12
+ # FIXME this is far too ambiguous. args should not mean different
13
+ # things in different contexts.
14
+ data_is_bytes = (data.nil? || Integer === data)
15
+ @bytes = data_is_bytes ? data : data.to_s.length
16
+ @data = data_is_bytes ? nil : data
17
+ @type = type
18
+ @last_modified_time = last_modified_time.utc
19
+ end
20
+
21
+ def data=(data)
22
+ @data = data
23
+ @bytes = @data.nil? ? nil : data.length
24
+ end
25
+
26
+ def passive?
27
+ @type == :passive
28
+ end
29
+
30
+ def active?
31
+ @type == :active
32
+ end
33
+ end
34
+ end
@@ -0,0 +1,340 @@
1
+ require 'socket'
2
+ require 'thread'
3
+ require 'timeout'
4
+
5
+ module FakeFtp
6
+ class Server
7
+
8
+ attr_accessor :port, :passive_port
9
+ attr_reader :mode, :path
10
+
11
+ CMDS = %w(
12
+ acct
13
+ cwd
14
+ cdup
15
+ dele
16
+ list
17
+ mdtm
18
+ mkd
19
+ nlst
20
+ pass
21
+ pasv
22
+ port
23
+ pwd
24
+ quit
25
+ stor
26
+ retr
27
+ rnfr
28
+ rnto
29
+ type
30
+ user
31
+ )
32
+ LNBK = "\r\n"
33
+
34
+ def initialize(control_port = 21, data_port = nil, options = {})
35
+ self.port = control_port
36
+ self.passive_port = data_port
37
+ raise(Errno::EADDRINUSE, "#{port}") if !control_port.zero? && is_running?
38
+ raise(Errno::EADDRINUSE, "#{passive_port}") if passive_port && !passive_port.zero? && is_running?(passive_port)
39
+ @connection = nil
40
+ @options = options
41
+ @files = []
42
+ @mode = :active
43
+ @path = "/pub"
44
+ end
45
+
46
+ def files
47
+ @files.map(&:name)
48
+ end
49
+
50
+ def file(name)
51
+ @files.detect { |file| file.name == name }
52
+ end
53
+
54
+ def reset
55
+ @files.clear
56
+ end
57
+
58
+ def add_file(filename, data, last_modified_time = Time.now)
59
+ @files << FakeFtp::File.new(::File.basename(filename.to_s), data, @mode, last_modified_time)
60
+ end
61
+
62
+ def start
63
+ @started = true
64
+ @server = ::TCPServer.new('127.0.0.1', port)
65
+ @port = @server.addr[1]
66
+ @thread = Thread.new do
67
+ while @started
68
+ @client = @server.accept rescue nil
69
+ if @client
70
+ respond_with('220 Can has FTP?')
71
+ @connection = Thread.new(@client) do |socket|
72
+ while @started && !socket.nil? && !socket.closed?
73
+ input = socket.gets rescue nil
74
+ respond_with parse(input) if input
75
+ end
76
+ unless @client.nil?
77
+ @client.close unless @client.closed?
78
+ @client = nil
79
+ end
80
+ end
81
+ end
82
+ end
83
+ unless @server.nil?
84
+ @server.close unless @server.closed?
85
+ @server = nil
86
+ end
87
+ end
88
+
89
+ if passive_port
90
+ @data_server = ::TCPServer.new('127.0.0.1', passive_port)
91
+ @passive_port = @data_server.addr[1]
92
+ end
93
+ end
94
+
95
+ def stop
96
+ @started = false
97
+ @client.close if @client
98
+ @server.close if @server
99
+ @server = nil
100
+ @data_server.close if @data_server
101
+ @data_server = nil
102
+ end
103
+
104
+ def is_running?(tcp_port = nil)
105
+ tcp_port.nil? ? port_is_open?(port) : port_is_open?(tcp_port)
106
+ end
107
+
108
+ private
109
+
110
+ def respond_with(stuff)
111
+ @client.print stuff << LNBK unless stuff.nil? or @client.nil? or @client.closed?
112
+ end
113
+
114
+ def parse(request)
115
+ return if request.nil?
116
+ puts request if @options[:debug]
117
+ command = request[0, 4].downcase.strip
118
+ contents = request.split
119
+ message = contents[1..contents.length]
120
+ case command
121
+ when *CMDS
122
+ __send__ "_#{command}", *message
123
+ else
124
+ '500 Unknown command'
125
+ end
126
+ end
127
+
128
+
129
+ ## FTP commands
130
+ #
131
+ # Methods are prefixed with an underscore to avoid conflicts with internal server
132
+ # methods. Methods map 1:1 to FTP command words.
133
+ #
134
+ def _acct(*args)
135
+ '230 WHATEVER!'
136
+ end
137
+
138
+ def _cwd(*args)
139
+ @path = args[0]
140
+ @path = "/#{path}" if path[0].chr != "/"
141
+ '250 OK!'
142
+ end
143
+
144
+ def _cdup(*args)
145
+ '250 OK!'
146
+ end
147
+
148
+ def _list(*args)
149
+ wildcards = []
150
+ args.each do |arg|
151
+ next unless arg.include? '*'
152
+ wildcards << arg.gsub('*', '.*')
153
+ end
154
+
155
+ respond_with('425 Ain\'t no data port!') && return if active? && @active_connection.nil?
156
+
157
+ respond_with('150 Listing status ok, about to open data connection')
158
+ data_client = active? ? @active_connection : @data_server.accept
159
+
160
+ files = @files
161
+ if not wildcards.empty?
162
+ files = files.select do |f|
163
+ wildcards.any? { |wildcard| f.name =~ /#{wildcard}/ }
164
+ end
165
+ end
166
+ files = files.map do |f|
167
+ "-rw-r--r--\t1\towner\tgroup\t#{f.bytes}\t#{f.created.strftime('%b %d %H:%M')}\t#{f.name}\n"
168
+ end
169
+ data_client.write(files.join)
170
+ data_client.close
171
+ @active_connection = nil
172
+
173
+ '226 List information transferred'
174
+ end
175
+
176
+ def _mdtm(filename = '', local = false)
177
+ respond_with('501 No filename given') && return if filename.empty?
178
+ server_file = file(filename)
179
+ respond_with('550 File not found') && return if server_file.nil?
180
+
181
+ respond_with("213 #{server_file.last_modified_time.strftime("%Y%m%d%H%M%S")}")
182
+ end
183
+
184
+ def _nlst(*args)
185
+ respond_with('425 Ain\'t no data port!') && return if active? && @active_connection.nil?
186
+
187
+ respond_with('150 Listing status ok, about to open data connection')
188
+ data_client = active? ? @active_connection : @data_server.accept
189
+
190
+ data_client.write(files.join("\n"))
191
+ data_client.close
192
+ @active_connection = nil
193
+
194
+ '226 List information transferred'
195
+ end
196
+
197
+ def _pass(*args)
198
+ '230 logged in'
199
+ end
200
+
201
+ def _pasv(*args)
202
+ if passive_port
203
+ @mode = :passive
204
+ p1 = (passive_port / 256).to_i
205
+ p2 = passive_port % 256
206
+ "227 Entering Passive Mode (127,0,0,1,#{p1},#{p2})"
207
+ else
208
+ '502 Aww hell no, use Active'
209
+ end
210
+ end
211
+
212
+ def _port(remote = '')
213
+ remote = remote.split(',')
214
+ remote_port = remote[4].to_i * 256 + remote[5].to_i
215
+ unless @active_connection.nil?
216
+ @active_connection.close
217
+ @active_connection = nil
218
+ end
219
+ @mode = :active
220
+ @active_connection = ::TCPSocket.open('127.0.0.1', remote_port)
221
+ '200 Okay'
222
+ end
223
+
224
+ def _pwd(*args)
225
+ "257 \"#{path}\" is current directory"
226
+ end
227
+
228
+ def _quit(*args)
229
+ respond_with '221 OMG bye!'
230
+ @client.close if @client
231
+ @client = nil
232
+ end
233
+
234
+ def _retr(filename = '')
235
+ respond_with('501 No filename given') if filename.empty?
236
+
237
+ file = file(::File.basename(filename.to_s))
238
+ return respond_with('550 File not found') if file.nil?
239
+
240
+ respond_with('425 Ain\'t no data port!') && return if active? && @active_connection.nil?
241
+
242
+ respond_with('150 File status ok, about to open data connection')
243
+ data_client = active? ? @active_connection : @data_server.accept
244
+
245
+ data_client.write(file.data)
246
+
247
+ data_client.close
248
+ @active_connection = nil
249
+ '226 File transferred'
250
+ end
251
+
252
+ def _rnfr(rename_from='')
253
+ return '501 Send path name.' if rename_from.nil? || rename_from.size < 1
254
+
255
+ @rename_from = rename_from
256
+ '350 Send RNTO to complete rename.'
257
+ end
258
+
259
+ def _rnto(rename_to='')
260
+ return '501 Send path name.' if rename_to.nil? || rename_to.size < 1
261
+
262
+ return '503 Send RNFR first.' unless @rename_from
263
+
264
+ if file = file(@rename_from)
265
+ file.name = rename_to
266
+ @rename_from = nil
267
+ '250 Path renamed.'
268
+ else
269
+ @rename_from = nil
270
+ '550 File not found.'
271
+ end
272
+ end
273
+
274
+ def _stor(filename = '')
275
+ respond_with('425 Ain\'t no data port!') && return if active? && @active_connection.nil?
276
+
277
+ respond_with('125 Do it!')
278
+ data_client = active? ? @active_connection : @data_server.accept
279
+
280
+ data = data_client.read(nil).chomp
281
+ file = FakeFtp::File.new(::File.basename(filename.to_s), data, @mode)
282
+ @files << file
283
+
284
+ data_client.close
285
+ @active_connection = nil
286
+ '226 Did it!'
287
+ end
288
+
289
+ def _dele(filename = '')
290
+ files_to_delete = @files.select{ |file| file.name == filename }
291
+ return '550 Delete operation failed.' if files_to_delete.count == 0
292
+
293
+ @files = @files - files_to_delete
294
+
295
+ '250 Delete operation successful.'
296
+ end
297
+
298
+ def _type(type = 'A')
299
+ case type.to_s
300
+ when 'A'
301
+ '200 Type set to A.'
302
+ when 'I'
303
+ '200 Type set to I.'
304
+ else
305
+ '504 We don\'t allow those'
306
+ end
307
+ end
308
+
309
+ def _user(name = '')
310
+ (name.to_s == 'anonymous') ? '230 logged in' : '331 send your password'
311
+ end
312
+
313
+ def _mkd(directory)
314
+ "257 OK!"
315
+ end
316
+
317
+ def active?
318
+ @mode == :active
319
+ end
320
+
321
+ private
322
+
323
+ def port_is_open?(port)
324
+ begin
325
+ Timeout::timeout(1) do
326
+ begin
327
+ s = TCPSocket.new("127.0.0.1", port)
328
+ s.close
329
+ return true
330
+ rescue Errno::ECONNREFUSED, Errno::EHOSTUNREACH
331
+ return false
332
+ end
333
+ end
334
+ rescue Timeout::Error
335
+ end
336
+
337
+ return false
338
+ end
339
+ end
340
+ end
@@ -0,0 +1,3 @@
1
+ module FakeFtp
2
+ VERSION = "0.1.1"
3
+ end
@@ -0,0 +1,468 @@
1
+ require "spec_helper.rb"
2
+
3
+ describe FakeFtp::Server, 'commands' do
4
+ let(:server) { FakeFtp::Server.new(21212, 21213) }
5
+ let(:client) { TCPSocket.open('127.0.0.1', 21212) }
6
+
7
+ before { server.start }
8
+
9
+ after {
10
+ client.close
11
+ server.stop
12
+ }
13
+
14
+ context 'general' do
15
+ it "should accept connections" do
16
+ expect(client.gets).to eql("220 Can has FTP?\r\n")
17
+ end
18
+
19
+ it "should get unknown command response when nothing is sent" do
20
+ client.gets
21
+ client.puts
22
+ expect(client.gets).to eql("500 Unknown command\r\n")
23
+ end
24
+
25
+ it "accepts QUIT" do
26
+ client.gets
27
+ client.puts "QUIT"
28
+ expect(client.gets).to eql("221 OMG bye!\r\n")
29
+ end
30
+
31
+ it "should accept multiple commands in one session" do
32
+ client.gets
33
+ client.puts "USER thing"
34
+ client.gets
35
+ client.puts "PASS thing"
36
+ client.gets
37
+ client.puts "ACCT thing"
38
+ client.gets
39
+ client.puts "USER thing"
40
+ end
41
+ end
42
+
43
+ context 'passive' do
44
+ it "accepts PASV" do
45
+ expect(server.mode).to eql(:active)
46
+ client.gets
47
+ client.puts "PASV"
48
+ expect(client.gets).to eql("227 Entering Passive Mode (127,0,0,1,82,221)\r\n")
49
+ expect(server.mode).to eql(:passive)
50
+ end
51
+
52
+ it "responds with correct PASV port" do
53
+ server.stop
54
+ server.passive_port = 21111
55
+ server.start
56
+ client.gets
57
+ client.puts "PASV"
58
+ expect(client.gets).to eql("227 Entering Passive Mode (127,0,0,1,82,119)\r\n")
59
+ end
60
+
61
+ it "does not accept PASV if no port set" do
62
+ server.stop
63
+ server.passive_port = nil
64
+ server.start
65
+ client.gets
66
+ client.puts "PASV"
67
+ expect(client.gets).to eql("502 Aww hell no, use Active\r\n")
68
+ end
69
+ end
70
+
71
+ context 'active' do
72
+ let!(:data_server) { ::TCPServer.new('127.0.0.1', 21216) }
73
+
74
+ before :each do
75
+ client.gets
76
+
77
+ @data_connection = Thread.new do
78
+ @server_client = data_server.accept
79
+ expect(@server_client).to_not be_nil
80
+ end
81
+ end
82
+
83
+ after :each do
84
+ data_server.close
85
+ end
86
+
87
+ it "accepts PORT and connects to port" do
88
+ client.puts "PORT 127,0,0,1,82,224"
89
+ expect(client.gets).to eql("200 Okay\r\n")
90
+
91
+ @data_connection.join
92
+ end
93
+
94
+ it "should switch to :active on port command" do
95
+ expect(server.mode).to eql(:active)
96
+ client.puts 'PASV'
97
+ client.gets
98
+ expect(server.mode).to eql(:passive)
99
+
100
+ client.puts "PORT 127,0,0,1,82,224"
101
+ expect(client.gets).to eql("200 Okay\r\n")
102
+
103
+ @data_connection.join
104
+
105
+ expect(server.mode).to eql(:active)
106
+ end
107
+ end
108
+
109
+ context 'authentication commands' do
110
+ before :each do
111
+ client.gets ## connection successful response
112
+ end
113
+
114
+ it "accepts USER" do
115
+ client.puts "USER some_dude"
116
+ expect(client.gets).to eql("331 send your password\r\n")
117
+ end
118
+
119
+ it "accepts anonymous USER" do
120
+ client.puts "USER anonymous"
121
+ expect(client.gets).to eql("230 logged in\r\n")
122
+ end
123
+
124
+ it "accepts PASS" do
125
+ client.puts "PASS password"
126
+ expect(client.gets).to eql("230 logged in\r\n")
127
+ end
128
+
129
+ it "accepts ACCT" do
130
+ client.puts "ACCT"
131
+ expect(client.gets).to eql("230 WHATEVER!\r\n")
132
+ end
133
+ end
134
+
135
+ context 'directory commands' do
136
+ before :each do
137
+ client.gets ## connection successful response
138
+ end
139
+
140
+ it "returns directory on PWD" do
141
+ client.puts "PWD"
142
+ expect(client.gets).to eql("257 \"/pub\" is current directory\r\n")
143
+ end
144
+
145
+ it "says OK to any CWD, CDUP, without doing anything" do
146
+ client.puts "CWD somewhere/else"
147
+ expect(client.gets).to eql("250 OK!\r\n")
148
+ client.puts "CDUP"
149
+ expect(client.gets).to eql("250 OK!\r\n")
150
+ end
151
+ end
152
+
153
+ context 'file commands' do
154
+ before :each do
155
+ client.gets ## connection successful response
156
+ end
157
+
158
+ it "accepts TYPE ascii" do
159
+ client.puts "TYPE A"
160
+ expect(client.gets).to eql("200 Type set to A.\r\n")
161
+ end
162
+
163
+ it "accepts TYPE image" do
164
+ client.puts "TYPE I"
165
+ expect(client.gets).to eql("200 Type set to I.\r\n")
166
+ end
167
+
168
+ it "does not accept TYPEs other than ascii or image" do
169
+ client.puts "TYPE E"
170
+ expect(client.gets).to eql("504 We don't allow those\r\n")
171
+ client.puts "TYPE N"
172
+ expect(client.gets).to eql("504 We don't allow those\r\n")
173
+ client.puts "TYPE T"
174
+ expect(client.gets).to eql("504 We don't allow those\r\n")
175
+ client.puts "TYPE C"
176
+ expect(client.gets).to eql("504 We don't allow those\r\n")
177
+ client.puts "TYPE L"
178
+ expect(client.gets).to eql("504 We don't allow those\r\n")
179
+ end
180
+
181
+ context 'passive' do
182
+ let(:data_client) { TCPSocket.open('127.0.0.1', 21213) }
183
+
184
+ before :each do
185
+ client.puts 'PASV'
186
+ expect(client.gets).to eql("227 Entering Passive Mode (127,0,0,1,82,221)\r\n")
187
+ end
188
+
189
+ it "accepts STOR with filename" do
190
+ client.puts "STOR some_file"
191
+ expect(client.gets).to eql("125 Do it!\r\n")
192
+ data_client.puts "1234567890"
193
+ data_client.close
194
+ expect(client.gets).to eql("226 Did it!\r\n")
195
+ expect(server.files).to include('some_file')
196
+ expect(server.file('some_file').bytes).to eql(10)
197
+ expect(server.file('some_file').data).to eql("1234567890")
198
+ end
199
+
200
+ it "accepts STOR with filename and trailing newline" do
201
+ client.puts "STOR some_file"
202
+ client.gets
203
+ # puts tries to be smart and only write a single \n
204
+ data_client.puts "1234567890\n\n"
205
+ data_client.close
206
+ expect(client.gets).to eql("226 Did it!\r\n")
207
+ expect(server.files).to include('some_file')
208
+ expect(server.file('some_file').bytes).to eql(11)
209
+ expect(server.file('some_file').data).to eql("1234567890\n")
210
+ end
211
+
212
+ it "accepts STOR with filename and long file" do
213
+ client.puts "STOR some_file"
214
+ expect(client.gets).to eql("125 Do it!\r\n")
215
+ data_client.puts("1234567890" * 10_000)
216
+ data_client.close
217
+ expect(client.gets).to eql("226 Did it!\r\n")
218
+ expect(server.files).to include('some_file')
219
+ end
220
+
221
+ it "accepts STOR with streams" do
222
+ client.puts "STOR some_file"
223
+ expect(client.gets).to eql("125 Do it!\r\n")
224
+ data_client.write "1234567890"
225
+ data_client.flush
226
+ data_client.write "1234567890"
227
+ data_client.flush
228
+ data_client.close
229
+ expect(client.gets).to eql("226 Did it!\r\n")
230
+ expect(server.file('some_file').data).to eql("12345678901234567890")
231
+ end
232
+
233
+ it "does not accept RETR without a filename" do
234
+ client.puts "RETR"
235
+ expect(client.gets).to eql("501 No filename given\r\n")
236
+ end
237
+
238
+ it "does not serve files that do not exist" do
239
+ client.puts "RETR some_file"
240
+ expect(client.gets).to eql("550 File not found\r\n")
241
+ end
242
+
243
+ it "accepts RETR with a filename" do
244
+ server.add_file('some_file', '1234567890')
245
+ client.puts "RETR some_file"
246
+ expect(client.gets).to eql("150 File status ok, about to open data connection\r\n")
247
+ data = data_client.read(1024)
248
+ data_client.close
249
+ expect(data).to eql('1234567890')
250
+ expect(client.gets).to eql("226 File transferred\r\n")
251
+ end
252
+
253
+ it "accepts DELE with a filename" do
254
+ server.add_file('some_file', '1234567890')
255
+ client.puts "DELE some_file"
256
+ expect(client.gets).to eql("250 Delete operation successful.\r\n")
257
+ expect(server.files).to_not include('some_file')
258
+ end
259
+
260
+ it "gives error message when trying to delete a file that does not exist" do
261
+ client.puts "DELE non_existing_file"
262
+ expect(client.gets).to eql("550 Delete operation failed.\r\n")
263
+ end
264
+
265
+ it "accepts a LIST command" do
266
+ server.add_file('some_file', '1234567890')
267
+ server.add_file('another_file', '1234567890')
268
+ client.puts "LIST"
269
+ expect(client.gets).to eql("150 Listing status ok, about to open data connection\r\n")
270
+ data = data_client.read(2048)
271
+ data_client.close
272
+ expect(data).to eql([
273
+ "-rw-r--r--\t1\towner\tgroup\t10\t#{server.file('some_file').created.strftime('%b %d %H:%M')}\tsome_file\n",
274
+ "-rw-r--r--\t1\towner\tgroup\t10\t#{server.file('another_file').created.strftime('%b %d %H:%M')}\tanother_file\n",
275
+ ].join)
276
+ expect(client.gets).to eql("226 List information transferred\r\n")
277
+ end
278
+
279
+ it "accepts a LIST command with a wildcard argument" do
280
+ files = ['test.jpg', 'test-2.jpg', 'test.txt']
281
+ files.each do |file|
282
+ server.add_file(file, '1234567890')
283
+ end
284
+
285
+ client.puts "LIST *.jpg"
286
+ expect(client.gets).to eql("150 Listing status ok, about to open data connection\r\n")
287
+
288
+ data = data_client.read(2048)
289
+ data_client.close
290
+ expect(data).to eql(files[0,2].map do |file|
291
+ "-rw-r--r--\t1\towner\tgroup\t10\t#{server.file(file).created.strftime('%b %d %H:%M')}\t#{file}\n"
292
+ end.join)
293
+ expect(client.gets).to eql("226 List information transferred\r\n")
294
+ end
295
+
296
+ it "accepts a LIST command with multiple wildcard arguments" do
297
+ files = ['test.jpg', 'test.gif', 'test.txt']
298
+ files.each do |file|
299
+ server.add_file(file, '1234567890')
300
+ end
301
+
302
+ client.puts "LIST *.jpg *.gif"
303
+ expect(client.gets).to eql("150 Listing status ok, about to open data connection\r\n")
304
+
305
+ data = data_client.read(2048)
306
+ data_client.close
307
+ expect(data).to eql(files[0,2].map do |file|
308
+ "-rw-r--r--\t1\towner\tgroup\t10\t#{server.file(file).created.strftime('%b %d %H:%M')}\t#{file}\n"
309
+ end.join)
310
+ expect(client.gets).to eql("226 List information transferred\r\n")
311
+ end
312
+
313
+ it "accepts an NLST command" do
314
+ server.add_file('some_file', '1234567890')
315
+ server.add_file('another_file', '1234567890')
316
+ client.puts "NLST"
317
+ expect(client.gets).to eql("150 Listing status ok, about to open data connection\r\n")
318
+ data = data_client.read(1024)
319
+ data_client.close
320
+ expect(data).to eql("some_file\nanother_file")
321
+ expect(client.gets).to eql("226 List information transferred\r\n")
322
+ end
323
+
324
+ it "should allow mdtm" do
325
+ filename = "file.txt"
326
+ now = Time.now
327
+ server.add_file(filename, "some dummy content", now)
328
+ client.puts "MDTM #{filename}"
329
+ expect(client.gets).to eql("213 #{now.strftime("%Y%m%d%H%M%S")}\r\n")
330
+ end
331
+ end
332
+
333
+ context 'active' do
334
+ let!(:data_server) { ::TCPServer.new('127.0.0.1', 21216) }
335
+
336
+ before :each do
337
+ @data_connection = Thread.new do
338
+ @server_client = data_server.accept
339
+ end
340
+ end
341
+
342
+ after :each do
343
+ data_server.close
344
+ @data_connection = nil
345
+ end
346
+
347
+ it 'creates a directory on MKD' do
348
+ client.puts "MKD some_dir"
349
+ expect(client.gets).to eql("257 OK!\r\n")
350
+ end
351
+
352
+ it 'should save the directory after you CWD' do
353
+ client.puts "CWD /somewhere/else"
354
+ expect(client.gets).to eql("250 OK!\r\n")
355
+ client.puts "PWD"
356
+ expect(client.gets).to eql("257 \"/somewhere/else\" is current directory\r\n")
357
+ end
358
+
359
+ it 'CWD should add a / to the beginning of the directory' do
360
+ client.puts "CWD somewhere/else"
361
+ expect(client.gets).to eql("250 OK!\r\n")
362
+ client.puts "PWD"
363
+ expect(client.gets).to eql("257 \"/somewhere/else\" is current directory\r\n")
364
+ end
365
+
366
+ it 'should not change the directory on CDUP' do
367
+ client.puts "CDUP"
368
+ expect(client.gets).to eql("250 OK!\r\n")
369
+ client.puts "PWD"
370
+ expect(client.gets).to eql("257 \"/pub\" is current directory\r\n")
371
+ end
372
+
373
+ it "sends error message if no PORT received" do
374
+ client.puts "STOR some_file"
375
+ expect(client.gets).to eql("425 Ain't no data port!\r\n")
376
+ end
377
+
378
+ it "accepts STOR with filename" do
379
+ client.puts "PORT 127,0,0,1,82,224"
380
+ expect(client.gets).to eql("200 Okay\r\n")
381
+
382
+ client.puts "STOR some_other_file"
383
+ expect(client.gets).to eql("125 Do it!\r\n")
384
+
385
+ @data_connection.join
386
+ @server_client.print "12345"
387
+ @server_client.close
388
+
389
+ expect(client.gets).to eql("226 Did it!\r\n")
390
+ expect(server.files).to include('some_other_file')
391
+ expect(server.file('some_other_file').bytes).to eql(5)
392
+ end
393
+
394
+ it "accepts RETR with a filename" do
395
+ client.puts "PORT 127,0,0,1,82,224"
396
+ expect(client.gets).to eql("200 Okay\r\n")
397
+
398
+ server.add_file('some_file', '1234567890')
399
+ client.puts "RETR some_file"
400
+ expect(client.gets).to eql("150 File status ok, about to open data connection\r\n")
401
+
402
+ @data_connection.join
403
+ data = @server_client.read(1024)
404
+ @server_client.close
405
+
406
+ expect(data).to eql('1234567890')
407
+ expect(client.gets).to eql("226 File transferred\r\n")
408
+ end
409
+
410
+ it "accepts RNFR without filename" do
411
+ client.puts "RNFR"
412
+ expect(client.gets).to eql("501 Send path name.\r\n")
413
+ end
414
+
415
+ it "accepts RNTO without RNFR" do
416
+ client.puts "RNTO some_other_file"
417
+ expect(client.gets).to eql("503 Send RNFR first.\r\n")
418
+ end
419
+
420
+ it "accepts RNTO and RNFR without filename" do
421
+ client.puts "RNFR from_file"
422
+ expect(client.gets).to eql("350 Send RNTO to complete rename.\r\n")
423
+
424
+ client.puts "RNTO"
425
+ expect(client.gets).to eql("501 Send path name.\r\n")
426
+ end
427
+
428
+ it "accepts RNTO and RNFR for not existing file" do
429
+ client.puts "RNFR from_file"
430
+ expect(client.gets).to eql("350 Send RNTO to complete rename.\r\n")
431
+
432
+ client.puts "RNTO to_file"
433
+ expect(client.gets).to eql("550 File not found.\r\n")
434
+ end
435
+
436
+ it "accepts RNTO and RNFR" do
437
+ server.add_file('from_file', '1234567890')
438
+
439
+ client.puts "RNFR from_file"
440
+ expect(client.gets).to eql("350 Send RNTO to complete rename.\r\n")
441
+
442
+ client.puts "RNTO to_file"
443
+ expect(client.gets).to eql("250 Path renamed.\r\n")
444
+
445
+ expect(server.files).to include('to_file')
446
+ expect(server.files).to_not include('from_file')
447
+ end
448
+
449
+ it "accepts an NLST command" do
450
+ client.puts "PORT 127,0,0,1,82,224"
451
+ expect(client.gets).to eql("200 Okay\r\n")
452
+
453
+ server.add_file('some_file', '1234567890')
454
+ server.add_file('another_file', '1234567890')
455
+ client.puts "NLST"
456
+ expect(client.gets).to eql("150 Listing status ok, about to open data connection\r\n")
457
+
458
+ @data_connection.join
459
+ data = @server_client.read(1024)
460
+ @server_client.close
461
+
462
+ expect(data).to eql("some_file\nanother_file")
463
+ expect(client.gets).to eql("226 List information transferred\r\n")
464
+ end
465
+ end
466
+ end
467
+ end
468
+