Project

testftpd

0.01
No release in over 3 years
Low commit activity in last 3 years
Simple FTP server written in pure Ruby, allowing integration testing of FTP client code without mocks and stubs
2005
2006
2007
2008
2009
2010
2011
2012
2013
2014
2015
2016
2017
2018
2019
2020
2021
2022
2023
2024
 Dependencies

Development

>= 10.1.0
>= 2.14
~> 0.7.1
 Project Readme

TestFtpd

Gem Version Build Status

Simple FTP server written in pure Ruby.

The primary use case is for integration testing FTP client code in a Rails 3.1 codebase using RSpec 2.

Enough FTP commands are implemented to be useful, including:

port pasv user pass quit syst type
list retr stor dele size mdtm rnfr/rnto
pwd cdup cwd mkd rmd nlst

Usage

Update your Gemfile

group :test do
  gem 'testftpd', :require => false
end

Write some specs...

require 'spec_helper'
require 'testftpd'

describe 'Test all the things!' do
  let(:ftp_port) { 21212 }
  let(:ftp_root) { Rails.root.to_s }

  before do
    @ftp_server = TestFtpd::Server.new(port: ftp_port, root_dir: ftp_root)
    @ftp_server.start
  end

  after do
    @ftp_server.shutdown
  end

  it 'lists remote files' do
    ftp = Net::FTP.new
    ftp.connect('127.0.0.1', ftp_port)
    ftp.login('username', 'password')
    ftp.list.any? { |file| file ~= /Gemfile/ }.should be_true
  end
end

You can change the list command format by monkey-patching or stubbing. Heres a stubbing technique I've used:

require 'spec_helper'
require 'testftpd'

describe 'Test all the things!' do
  let(:ftp_port) { 21212 }
  let(:ftp_root) { Rails.root.to_s }

  before do
    @ftp_server = TestFtpd::Server.new(port: ftp_port, root_dir: ftp_root)
    @ftp_server.start
  end

  after do
    @ftp_server.shutdown
  end

  before :each do
    TestFtpd::FileSystemProvider.stub(:format_list_entry) do |entry|
      raw =  entry.ftp_date.strftime('%m-%d-%g  %I:%M%p') + ' '
      if entry.directory?
        raw += '    <DIR>            '
      else
        raw += entry.ftp_size.to_s.rjust(20, ' ') + ' '
      end
      raw += entry.ftp_name
      raw += "\r\n"
      raw
    end
  end

  it 'lists remote files' do
    ftp = Net::FTP.new
    ftp.connect('127.0.0.1', ftp_port)
    ftp.login('username', 'password')
    ftp.list.any? { |file| file ~= /Gemfile/ }.should be_true
  end

This will most likely make it into the TestFtpd code base as a configurable option, stay tuned.

Todo

  • more tests
  • add simple authentication provider
  • implement more FTP commands

Acknowledgements

This code builds upon Rubtsov Vitaly' excellent project dyn-ftp-serv created in late 2007.

Also Francis Hwang who originally adapted dyn-ftp-serv, and gave me a head start for this project.

Contributers

  • Christian Schulze

License

Released under the MIT license. Please see the LICENSE file for more information.