diff --git a/Rakefile b/Rakefile
index 72ae223f5e2d95c320dd749503f8c09b87a92250..cef597657fc95c52de7c0a4e75693e9bbcc7c6ef 100644
--- a/Rakefile
+++ b/Rakefile
@@ -83,6 +83,7 @@ end
 
 Rake::TestTask.new do |t|
   t.pattern = "test/unit/*_test.rb"
+  t.warning = false
 end
 task :default => :test
 
diff --git a/bin/leap b/bin/leap
index 724716823797a453ec7543cdb2484f90a18c0221..b2eca90f01fa3b85155cf7e77767c9577014eec3 100755
--- a/bin/leap
+++ b/bin/leap
@@ -14,6 +14,7 @@ else
   $VERBOSE=nil
   DEBUG=false
 end
+TEST = false
 
 LEAP_CLI_BASE_DIR = File.expand_path('..', File.dirname(File.symlink?(__FILE__) ? File.readlink(__FILE__) : __FILE__))
 
@@ -90,6 +91,8 @@ module LeapCli::Commands
     end
     if DEBUG
       raise exc
+    else
+      exit(1)
     end
   end
 end
diff --git a/lib/leap_cli/bootstrap.rb b/lib/leap_cli/bootstrap.rb
index f33aa4282e4b74c2aa9c5244c5f6a583d10647f0..75edf5b7f7a58f8dd97d966c1c48e9276a4be49f 100644
--- a/lib/leap_cli/bootstrap.rb
+++ b/lib/leap_cli/bootstrap.rb
@@ -159,7 +159,9 @@ module LeapCli
     # Yes, hacky.
     #
     def leapfile_optional?(argv)
-      if argv.include?('--version')
+      if TEST
+        return true
+      elsif argv.include?('--version')
         return true
       else
         without_flags = argv.select {|i| i !~ /^-/}
diff --git a/lib/leap_cli/core_ext/hash.rb b/lib/leap_cli/core_ext/hash.rb
index 7df33b260e4309d9a9789148713e7c775d413ecd..4eb3af3d6fd19aff7a6b73bf4b95619b9028037f 100644
--- a/lib/leap_cli/core_ext/hash.rb
+++ b/lib/leap_cli/core_ext/hash.rb
@@ -32,4 +32,23 @@ class Hash
     replace(deep_merge(other_hash))
   end
 
+  #
+  # A recursive symbolize_keys
+  #
+  unless Hash.method_defined?(:symbolize_keys)
+    def symbolize_keys
+      self.inject({}) {|result, (key, value)|
+        new_key = case key
+                  when String then key.to_sym
+                  else key
+                  end
+        new_value = case value
+                    when Hash then symbolize_keys(value)
+                    else value
+                    end
+        result[new_key] = new_value
+        result
+      }
+    end
+  end
 end
diff --git a/lib/leap_cli/leapfile.rb b/lib/leap_cli/leapfile.rb
index 3dadf664ba0879f17ad863d54304a9b347ed2d72..0b56b710c26e9acc4255eb63a4f8d4b646d33cd7 100644
--- a/lib/leap_cli/leapfile.rb
+++ b/lib/leap_cli/leapfile.rb
@@ -150,11 +150,6 @@ module LeapCli
       return search_dir
     end
 
-    # to be overridden
-    def validate
-      return true
-    end
-
     def method_missing(method, *args)
       if method =~ /=$/
         self.instance_variable_set('@' + method.to_s.sub('=',''), args.first)
diff --git a/lib/leap_cli/log.rb b/lib/leap_cli/log.rb
index 203d92e2c357517a10c05924c32b2b486eeaaa89..01d372ccb5315e28cf0d6ba03489c7140c7ba22a 100644
--- a/lib/leap_cli/log.rb
+++ b/lib/leap_cli/log.rb
@@ -89,7 +89,7 @@ module LeapCli
       if title
         title = title.to_s
       end
-      unless message && @log_level >= level
+      if @log_level < level || (title.nil? && message.nil?)
         return
       end
 
diff --git a/lib/leap_cli/path.rb b/lib/leap_cli/path.rb
index 11fc0f16bbc1b85820cf92c8a12fec456241f7a3..a78dbd2c922f83448b814d6ec17784ed22209bb2 100644
--- a/lib/leap_cli/path.rb
+++ b/lib/leap_cli/path.rb
@@ -3,7 +3,7 @@ require 'fileutils'
 module LeapCli; module Path
 
   def self.platform
-    @platform
+    @platform ||= nil
   end
 
   def self.provider_base
diff --git a/test/test_helper.rb b/test/test_helper.rb
index f7ec6d9f9e96a991f3b22b4008f91a4e9a2001c7..e0cd1e13621c4dc87bb644316796414a1d7926fd 100644
--- a/test/test_helper.rb
+++ b/test/test_helper.rb
@@ -7,6 +7,7 @@ require 'gli'
 require 'fileutils'
 
 DEBUG = true
+TEST  = true
 
 module LeapCli::Commands
   extend GLI::App
@@ -19,7 +20,7 @@ class Minitest::Test
 
   def initialize(*args)
     super(*args)
-    LeapCli::Bootstrap::setup([], test_provider_path)
+    LeapCli::Bootstrap::setup([], provider_path)
     LeapCli::Bootstrap::load_libraries(LeapCli::Commands)
   end
 
@@ -43,33 +44,56 @@ class Minitest::Test
   end
 
   def leap_bin(*args)
-    `cd #{test_provider_path} && #{ruby_path} #{base_path}/bin/leap --no-color #{args.join ' '}`
+    cmd = "cd #{provider_path} && #{base_path}/bin/leap --no-color #{args.join ' '}"
+    `#{cmd}`
   end
 
-  def test_provider_path
+  def leap_bin!(*args)
+    output = leap_bin(*args)
+    exit_code = $?
+    assert_equal 0, exit_code,
+      "The command `leap #{args.join(' ')}` should have exited 0 " +
+      "(was #{exit_code}).\n" +
+      "Output was: #{output}"
+    output
+  end
+
+  def provider_path
     "#{base_path}/test/provider"
   end
 
+  #
+  # for tests, we assume that the leap_platform code is
+  # in a sister directory to leap_cli.
+  #
+  def platform_path
+    "#{base_path}/../leap_platform"
+  end
+
   def cleanup_files(*args)
-    Dir.chdir(test_provider_path) do
+    Dir.chdir(provider_path) do
       args.each do |file|
         FileUtils.rm_r(file) if File.exist?(file)
       end
     end
   end
 
+  #
+  # we no longer support ruby 1.8, but this might be useful in the future
+  #
   def with_multiple_rubies(&block)
-    if ENV["RUBY"]
-      ENV["RUBY"].split(',').each do |ruby|
-        self.ruby_path = `which #{ruby}`.strip
-        next unless ruby_path.chars.any?
-        yield
-      end
-    else
-      self.ruby_path = `which ruby`.strip
-      yield
-    end
-    self.ruby_path = ""
+    yield
+  #  if ENV["RUBY"]
+  #    ENV["RUBY"].split(',').each do |ruby|
+  #      self.ruby_path = `which #{ruby}`.strip
+  #      next unless ruby_path.chars.any?
+  #      yield
+  #    end
+  #  else
+  #    self.ruby_path = `which ruby`.strip
+  #    yield
+  #  end
+  #  self.ruby_path = ""
   end
 
 end
diff --git a/test/unit/command_line_test.rb b/test/unit/command_line_test.rb
index bab8792f2c121ed98cc357c64273211438718800..0f452abe82dc4643313ac2f530bb05b18fe50bac 100644
--- a/test/unit/command_line_test.rb
+++ b/test/unit/command_line_test.rb
@@ -1,4 +1,4 @@
-require File.expand_path('../test_helper', __FILE__)
+require_relative 'test_helper'
 
 class CommandLineTest < Minitest::Test
 
diff --git a/test/unit/config_object_list_test.rb b/test/unit/config_object_list_test.rb
index c4f37d89ba5ae62f41698242620d84834c4a23c5..042a742f91a837b7e79428f4febcac8708f6231e 100644
--- a/test/unit/config_object_list_test.rb
+++ b/test/unit/config_object_list_test.rb
@@ -1,4 +1,4 @@
-require File.expand_path('../test_helper', __FILE__)
+require_relative 'test_helper'
 
 class ConfigObjectListTest < Minitest::Test
 
diff --git a/test/unit/config_object_test.rb b/test/unit/config_object_test.rb
index 54b45d146ac634377294f6a19237b05fee80807f..88e11e624277c2d943de1ccf9b1c2647227ddabe 100644
--- a/test/unit/config_object_test.rb
+++ b/test/unit/config_object_test.rb
@@ -1,4 +1,4 @@
-require File.expand_path('../test_helper', __FILE__)
+require_relative 'test_helper'
 
 class ConfigObjectTest < Minitest::Test
 
diff --git a/test/unit/quick_start_test.rb b/test/unit/quick_start_test.rb
new file mode 100644
index 0000000000000000000000000000000000000000..d26f9c85c1f687cfab51d9747876862c46555521
--- /dev/null
+++ b/test/unit/quick_start_test.rb
@@ -0,0 +1,127 @@
+require_relative 'test_helper'
+
+#
+# Runs all the commands in https://leap.se/quick-start
+#
+
+Minitest.after_run {
+  FileUtils.rm_r(QuickStartTest::TMP_PROVIDER)
+}
+
+class QuickStartTest < Minitest::Test
+
+  # very reasonable to have ordered tests in this case, actually
+  i_suck_and_my_tests_are_order_dependent!
+
+  TMP_PROVIDER = Dir.mktmpdir("test_leap_provider_")
+
+  #
+  # use minimal bit sizes for our test.
+  #
+  PROVIDER_JSON = <<HERE
+{
+  "domain": "example.org",
+  "name": {
+    "en": "Example"
+  },
+  "description": {
+    "en": "Example"
+  },
+  "languages": ["en"],
+  "default_language": "en",
+  "enrollment_policy": "open",
+  "contacts": {
+    "default": "root@localhost"
+  },
+  "ca": {
+    "bit_size": 1024,
+    "client_certificates": {
+      "bit_size": 1024,
+      "digest": "SHA1",
+      "life_span": "100 years"
+    },
+    "life_span": "100 years",
+    "server_certificates": {
+      "bit_size": 1024,
+      "digest": "SHA1",
+      "life_span": "100 years"
+    }
+  }
+}
+HERE
+
+  def provider_path
+    TMP_PROVIDER
+  end
+
+  def test_01_new
+    output = leap_bin! "new --contacts me@example.org --domain example.org --name Example --platform='#{platform_path}' ."
+    assert_file "Leapfile"
+    assert_file "provider.json"
+    assert_dir "nodes"
+    File.write(File.join(provider_path, 'provider.json'), PROVIDER_JSON)
+  end
+
+  def test_02_ca
+    leap_bin! "cert ca"
+    assert_dir "files/ca"
+    assert_file "files/ca/ca.crt"
+    assert_file "files/ca/ca.key"
+  end
+
+  def test_03_csr
+    leap_bin! "cert csr"
+    assert_file "files/cert/example.org.csr"
+    assert_file "files/cert/example.org.crt"
+    assert_file "files/cert/example.org.key"
+  end
+
+  def test_04_nodes
+    leap_bin! "node add wildebeest ip_address:1.1.1.2 services:webapp,couchdb"
+    leap_bin! "node add hippo ip_address:1.1.1.3 services:static"
+    assert_file "nodes/wildebeest.json"
+    assert_dir "files/nodes/wildebeest"
+    assert_file "files/nodes/wildebeest/wildebeest.crt"
+    assert_file "files/nodes/wildebeest/wildebeest.key"
+  end
+
+  def test_05_compile
+    user_dir = File.join(provider_path, 'users', 'dummy')
+    user_key = File.join(user_dir, 'dummy_ssh.pub')
+    FileUtils.mkdir_p(user_dir)
+    File.write(user_key, 'ssh-rsa dummydummydummy')
+
+    leap_bin! "compile"
+    assert_file "hiera/wildebeest.yaml"
+    assert_file "hiera/hippo.yaml"
+  end
+
+  def test_06_rename
+    leap_bin! "node mv hippo hippopotamus"
+    assert_file "nodes/hippopotamus.json"
+    assert_dir "files/nodes/hippopotamus"
+    assert_file "files/nodes/hippopotamus/hippopotamus.key"
+  end
+
+  def test_07_rm
+    leap_bin! "node rm hippopotamus"
+    assert_file_missing "nodes/hippopotamus.json"
+    assert_file_missing "files/nodes/hippopotamus/hippopotamus.key"
+  end
+
+  def assert_file(path)
+    assert File.exist?(File.join(provider_path, path)), "The file `#{path}` should exist in #{provider_path}. Actual: \n#{provider_files}"
+  end
+
+  def assert_file_missing(path)
+    assert !File.exist?(File.join(provider_path, path)), "The file `#{path}` should NOT exist in #{provider_path}."
+  end
+
+  def assert_dir(path)
+    assert Dir.exist?(File.join(provider_path, path)), "The directory `#{path}` should exist in #{provider_path}. Actual: \n#{provider_files}"
+  end
+
+  def provider_files
+    `cd #{provider_path} && find .`
+  end
+end
diff --git a/test/unit/test_helper.rb b/test/unit/test_helper.rb
index 25a36de7ca8b229777869b22dff6bec78593baf1..057e4b7dfddab6cf8ac25a96f75c8d15f84acf8b 100644
--- a/test/unit/test_helper.rb
+++ b/test/unit/test_helper.rb
@@ -1 +1 @@
-require File.expand_path('../../test_helper', __FILE__)
+require_relative '../test_helper'