itamae-spec 0.0.2

Sign up to get free protection for your applications and to get access to all the features.
Files changed (77) hide show
  1. checksums.yaml +7 -0
  2. data/.gitignore +14 -0
  3. data/.rspec +2 -0
  4. data/Gemfile +7 -0
  5. data/LICENSE.txt +22 -0
  6. data/README.md +42 -0
  7. data/Rakefile +47 -0
  8. data/bin/itamae-spec +4 -0
  9. data/itamae-spec.gemspec +36 -0
  10. data/lib/itamae-spec.rb +10 -0
  11. data/lib/itamae-spec/cli.rb +19 -0
  12. data/lib/itamae-spec/generators.rb +20 -0
  13. data/lib/itamae-spec/generators/cookbook.rb +10 -0
  14. data/lib/itamae-spec/generators/project.rb +10 -0
  15. data/lib/itamae-spec/generators/templates/cookbook/attributes/.keep +0 -0
  16. data/lib/itamae-spec/generators/templates/cookbook/recipes/default.rb +0 -0
  17. data/lib/itamae-spec/generators/templates/cookbook/recipes/files/.keep +0 -0
  18. data/lib/itamae-spec/generators/templates/cookbook/recipes/templates/.keep +0 -0
  19. data/lib/itamae-spec/generators/templates/cookbook/spec/default_spec.rb +0 -0
  20. data/lib/itamae-spec/generators/templates/project/.rspec +2 -0
  21. data/lib/itamae-spec/generators/templates/project/Gemfile +3 -0
  22. data/lib/itamae-spec/generators/templates/project/Project.json +1 -0
  23. data/lib/itamae-spec/generators/templates/project/Rakefile +9 -0
  24. data/lib/itamae-spec/generators/templates/project/cookbooks/sample/attributes/.keep +0 -0
  25. data/lib/itamae-spec/generators/templates/project/cookbooks/sample/attributes/default.json +5 -0
  26. data/lib/itamae-spec/generators/templates/project/cookbooks/sample/recipes/default.rb +7 -0
  27. data/lib/itamae-spec/generators/templates/project/cookbooks/sample/recipes/files/.keep +0 -0
  28. data/lib/itamae-spec/generators/templates/project/cookbooks/sample/recipes/templates/.keep +0 -0
  29. data/lib/itamae-spec/generators/templates/project/cookbooks/sample/spec/default_spec.rb +9 -0
  30. data/lib/itamae-spec/generators/templates/project/environments/.keep +0 -0
  31. data/lib/itamae-spec/generators/templates/project/environments/sample.json +7 -0
  32. data/lib/itamae-spec/generators/templates/project/keys/.keep +0 -0
  33. data/lib/itamae-spec/generators/templates/project/nodes/.keep +0 -0
  34. data/lib/itamae-spec/generators/templates/project/nodes/sample.json +10 -0
  35. data/lib/itamae-spec/generators/templates/project/roles/.keep +0 -0
  36. data/lib/itamae-spec/generators/templates/project/roles/sample.json +5 -0
  37. data/lib/itamae-spec/generators/templates/project/spec/spec_helper.rb +41 -0
  38. data/lib/itamae-spec/generators/templates/project/tmp-nodes/.keep +0 -0
  39. data/lib/itamae-spec/logger.rb +76 -0
  40. data/lib/itamae-spec/resource.rb +2 -0
  41. data/lib/itamae-spec/resource/http_request.rb +71 -0
  42. data/lib/itamae-spec/resource/s3_file.rb +31 -0
  43. data/lib/itamae-spec/task/base.rb +90 -0
  44. data/lib/itamae-spec/task/base_task.rb +148 -0
  45. data/lib/itamae-spec/task/itamae_task.rb +112 -0
  46. data/lib/itamae-spec/task/local_itamae_task.rb +84 -0
  47. data/lib/itamae-spec/task/local_serverspec_task.rb +125 -0
  48. data/lib/itamae-spec/task/serverspec_task.rb +111 -0
  49. data/lib/itamae-spec/version.rb +3 -0
  50. data/lib/itamae-spec/version.txt +1 -0
  51. data/spec/integration/Vagrantfile +35 -0
  52. data/spec/integration/default_spec.rb +226 -0
  53. data/spec/integration/recipes/default.rb +423 -0
  54. data/spec/integration/recipes/default2.rb +6 -0
  55. data/spec/integration/recipes/define/default.rb +6 -0
  56. data/spec/integration/recipes/define/files/remote_file_in_definition +1 -0
  57. data/spec/integration/recipes/dry_run.rb +6 -0
  58. data/spec/integration/recipes/files/remote_file_auto +1 -0
  59. data/spec/integration/recipes/hello.erb +6 -0
  60. data/spec/integration/recipes/hello.txt +1 -0
  61. data/spec/integration/recipes/included.rb +9 -0
  62. data/spec/integration/recipes/node.json +3 -0
  63. data/spec/integration/recipes/redefine.rb +20 -0
  64. data/spec/integration/recipes/templates/template_auto.erb +6 -0
  65. data/spec/integration/spec_helper.rb +42 -0
  66. data/spec/unit/lib/itamae/backend_spec.rb +95 -0
  67. data/spec/unit/lib/itamae/handler/base_spec.rb +34 -0
  68. data/spec/unit/lib/itamae/handler/fluentd_spec.rb +19 -0
  69. data/spec/unit/lib/itamae/handler_proxy_spec.rb +38 -0
  70. data/spec/unit/lib/itamae/handler_spec.rb +11 -0
  71. data/spec/unit/lib/itamae/node_spec.rb +14 -0
  72. data/spec/unit/lib/itamae/recipe_spec.rb +6 -0
  73. data/spec/unit/lib/itamae/resource/base_spec.rb +127 -0
  74. data/spec/unit/lib/itamae/resource_spec.rb +23 -0
  75. data/spec/unit/lib/itamae/runner_spec.rb +32 -0
  76. data/spec/unit/spec_helper.rb +23 -0
  77. metadata +315 -0
@@ -0,0 +1,84 @@
1
+ require 'itamae-spec/task/base_task'
2
+
3
+ module ItamaeSpec
4
+ module Task
5
+ class LocalItamaeTask < BaseTask
6
+ def create_itamae_command(node_name, hash)
7
+ command = 'bundle exec itamae-spec local'
8
+ command << " -j tmp-nodes/#{node_name}.json"
9
+
10
+ hash[:environments][:shell] = ENV['shell'] if ENV['shell']
11
+ command << if hash[:environments][:shell]
12
+ " --shell=#{hash[:environments][:shell]}"
13
+ else
14
+ ' --shell=bash'
15
+ end
16
+
17
+ command << ' --dry-run' if ENV['dry-run'] == 'true'
18
+ command << ' --log-level=debug' if ENV['debug'] == 'true'
19
+ command
20
+ end
21
+
22
+ Itamae.logger.formatter.colored = true
23
+ task = LocalItamaeTask.new
24
+
25
+ namespace :local_itamae do
26
+ all = []
27
+
28
+ Dir.glob('nodes/**/*.json').each do |node_file|
29
+ begin
30
+ node_name = File.basename(node_file, '.json')
31
+ node = task.load_node_attributes(node_file)
32
+ node_short = node[:environments][:hostname].split('.')[0]
33
+ rescue => e
34
+ Itamae.logger.error e.inspect
35
+ Itamae.logger.info "From node file: #{node_file}"
36
+ exit 2
37
+ end
38
+
39
+ all << node_short
40
+ desc 'Itamae local to all nodes'
41
+ task 'all' => all
42
+
43
+ desc "Itamae local to #{node_name}"
44
+ task node_short do
45
+ Itamae.logger.color(:cyan) do
46
+ Itamae.logger.info "Start local_itamae_task to #{node[:environments][:hostname]}"
47
+ end
48
+
49
+ begin
50
+ run_list = task.load_run_list(node_file)
51
+ environments = task.load_environments(node)
52
+ recipe_attributes_list = task.load_recipe_attributes(run_list)
53
+
54
+ merged_recipe = task.merge_attributes(recipe_attributes_list)
55
+ merged_environments = task.merge_attributes(merged_recipe, environments)
56
+ attributes = task.merge_attributes(merged_environments, node)
57
+ task.create_tmp_nodes(node_name, attributes)
58
+
59
+ command = task.create_itamae_command(node_name, attributes)
60
+ command_recipe = task.list_recipe_filepath(run_list)
61
+ command_recipe.sort_by! {|item| File.dirname(item) }
62
+ command << command_recipe.join
63
+
64
+ task.runner_display(attributes[:run_list], run_list, command)
65
+ st = system command
66
+ if st
67
+ Itamae.logger.color(:green) do
68
+ Itamae.logger.info 'local_itamae_task is completed.'
69
+ end
70
+ else
71
+ Itamae.logger.error 'local_itamae_task is failed.'
72
+ exit 1
73
+ end
74
+ rescue => e
75
+ Itamae.logger.error e.inspect
76
+ Itamae.logger.info "From node file: #{node_file}"
77
+ exit 2
78
+ end
79
+ end
80
+ end
81
+ end
82
+ end
83
+ end
84
+ end
@@ -0,0 +1,125 @@
1
+ require 'itamae-spec/task/base_task'
2
+
3
+ module ItamaeSpec
4
+ module Task
5
+ class LocalServerspecTask < BaseTask
6
+ ChangeTargetError = Class.new(StandardError)
7
+ LoadSpecError = Class.new(StandardError)
8
+
9
+ def create_spec_command(node_name, hash)
10
+ ENV['TARGET_HOST'] = if hash[:environments][:local_ipv4].nil?
11
+ hash[:environments][:hostname]
12
+ else
13
+ hash[:environments][:local_ipv4]
14
+ end
15
+
16
+ ENV['NODE_FILE'] = "tmp-nodes/#{node_name}.json"
17
+ ENV['SUDO_PASSWORD'] = hash[:environments][:sudo_password]
18
+ ENV['LOCAL_MODE'] = 'enable local mode'
19
+
20
+ command = 'bundle exec rspec'
21
+ end
22
+
23
+ def list_recipe_filepath(run_list)
24
+ recipes = []
25
+ run_list.each do |recipe|
26
+ target_list = Dir.glob("cookbooks/#{recipe.keys.join}/spec/#{recipe.values.join}_spec.rb")
27
+
28
+ raise LoadSpecError, "#{recipe.to_a.join('::')} cookbook or spec does not exist." if target_list.empty?
29
+
30
+ target_list.each do |target|
31
+ recipes << " #{target}"
32
+ end
33
+ end
34
+
35
+ recipes
36
+ end
37
+
38
+ Itamae.logger.formatter.colored = true
39
+ task = LocalServerspecTask.new
40
+
41
+ namespace :local_spec do
42
+ all = []
43
+
44
+ begin
45
+ project = { project: ARGV[1] }
46
+
47
+ if (ARGV[0] == '-T' || ARGV[0] == '--tasks') && !project[:project].nil?
48
+ unless Dir.exist?("nodes/#{project[:project]}")
49
+ raise ChangeTargetError, "'#{project[:project]}' project is not exist."
50
+ end
51
+
52
+ File.open 'Project.json', 'w' do |f|
53
+ f.flock File::LOCK_EX
54
+ f.puts project.to_json
55
+ f.flock File::LOCK_UN
56
+ end
57
+
58
+ Itamae.logger.color(:green) do
59
+ Itamae.logger.info "Changed target mode '#{project[:project]}'"
60
+ end
61
+ end
62
+
63
+ resp = JSON.parse(File.read('Project.json'))
64
+ target = resp['project'] << '/**'
65
+ rescue => e
66
+ Itamae.logger.error e.inspect
67
+ exit 2
68
+ end
69
+
70
+ Dir.glob("nodes/#{target}/*.json").each do |node_file|
71
+ begin
72
+ node_name = File.basename(node_file, '.json')
73
+ node = task.load_node_attributes(node_file)
74
+ node_short = node[:environments][:hostname].split('.')[0]
75
+ rescue => e
76
+ Itamae.logger.error e.inspect
77
+ Itamae.logger.info "From node file: #{node_file}"
78
+ exit 2
79
+ end
80
+
81
+ all << node_short
82
+ desc 'Serverspec to all nodes'
83
+ task 'all' => all
84
+
85
+ desc "Serverspec to #{node_name}"
86
+ task node_short do
87
+ Itamae.logger.color(:cyan) do
88
+ Itamae.logger.info "Start local_serverspec_task to #{node[:environments][:hostname]}"
89
+ end
90
+
91
+ begin
92
+ run_list = task.load_run_list(node_file)
93
+ environments = task.load_environments(node)
94
+ recipe_attributes_list = task.load_recipe_attributes(run_list)
95
+
96
+ merged_recipe = task.merge_attributes(recipe_attributes_list)
97
+ merged_environments = task.merge_attributes(merged_recipe, environments)
98
+ attributes = task.merge_attributes(merged_environments, node)
99
+ task.create_tmp_nodes(node_name, attributes)
100
+
101
+ command = task.create_spec_command(node_name, attributes)
102
+ command_recipe = task.list_recipe_filepath(run_list)
103
+ command << command_recipe.join
104
+
105
+ task.runner_display(attributes[:run_list], run_list, command)
106
+ st = system command
107
+ if st
108
+ Itamae.logger.color(:green) do
109
+ Itamae.logger.info 'local_serverspec_task is completed.'
110
+ end
111
+ else
112
+ Itamae.logger.error 'local_serverspec_task is failed.'
113
+ exit 1
114
+ end
115
+ rescue => e
116
+ Itamae.logger.error e.inspect
117
+ Itamae.logger.info "From node file: #{node_file}"
118
+ exit 2
119
+ end
120
+ end
121
+ end
122
+ end
123
+ end
124
+ end
125
+ end
@@ -0,0 +1,111 @@
1
+ require 'itamae-spec/task/base_task'
2
+
3
+ module ItamaeSpec
4
+ module Task
5
+ class ServerspecTask < BaseTask
6
+ ChangeTargetError = Class.new(StandardError)
7
+ LoadSpecError = Class.new(StandardError)
8
+
9
+ def list_recipe_filepath(run_list)
10
+ recipes = []
11
+ run_list.each do |recipe|
12
+ target_list = Dir.glob("cookbooks/#{recipe.keys.join}/spec/#{recipe.values.join}_spec.rb")
13
+
14
+ raise LoadSpecError, "#{recipe.to_a.join('::')} cookbook or spec does not exist." if target_list.empty?
15
+
16
+ target_list.each do |target|
17
+ recipes << " #{target}"
18
+ end
19
+ end
20
+
21
+ recipes
22
+ end
23
+
24
+ Itamae.logger.formatter.colored = true
25
+ task = ServerspecTask.new
26
+
27
+ namespace :spec do
28
+ all = []
29
+
30
+ begin
31
+ project = { project: ARGV[1] }
32
+
33
+ if (ARGV[0] == '-T' || ARGV[0] == '--tasks') && !project[:project].nil?
34
+ unless Dir.exist?("nodes/#{project[:project]}")
35
+ raise ChangeTargetError, "'#{project[:project]}' project is not exist."
36
+ end
37
+
38
+ File.open 'Project.json', 'w' do |f|
39
+ f.flock File::LOCK_EX
40
+ f.puts project.to_json
41
+ f.flock File::LOCK_UN
42
+ end
43
+
44
+ Itamae.logger.color(:green) do
45
+ Itamae.logger.info "Changed target mode '#{project[:project]}'"
46
+ end
47
+ end
48
+
49
+ resp = JSON.parse(File.read('Project.json'))
50
+ target = resp['project'] << '/**'
51
+ rescue => e
52
+ Itamae.logger.error e.inspect
53
+ exit 2
54
+ end
55
+
56
+ Dir.glob("nodes/#{target}/*.json").each do |node_file|
57
+ begin
58
+ node_name = File.basename(node_file, '.json')
59
+ node = task.load_node_attributes(node_file)
60
+ node_short = node[:environments][:hostname].split('.')[0]
61
+ rescue => e
62
+ Itamae.logger.error e.inspect
63
+ Itamae.logger.info "From node file: #{node_file}"
64
+ exit 2
65
+ end
66
+
67
+ all << node_short
68
+ desc 'Serverspec to all nodes'
69
+ task 'all' => all
70
+
71
+ desc "Serverspec to #{node_name}"
72
+ task node_short do
73
+ Itamae.logger.color(:cyan) do
74
+ Itamae.logger.info "Start serverspec_task to #{node[:environments][:hostname]}"
75
+ end
76
+
77
+ begin
78
+ run_list = task.load_run_list(node_file)
79
+ environments = task.load_environments(node)
80
+ recipe_attributes_list = task.load_recipe_attributes(run_list)
81
+
82
+ merged_recipe = task.merge_attributes(recipe_attributes_list)
83
+ merged_environments = task.merge_attributes(merged_recipe, environments)
84
+ attributes = task.merge_attributes(merged_environments, node)
85
+ task.create_tmp_nodes(node_name, attributes)
86
+
87
+ command = task.create_spec_command(node_name, attributes)
88
+ command_recipe = task.list_recipe_filepath(run_list)
89
+ command << command_recipe.join
90
+
91
+ task.runner_display(attributes[:run_list], run_list, command)
92
+ st = system command
93
+ if st
94
+ Itamae.logger.color(:green) do
95
+ Itamae.logger.info 'serverspec_task is completed.'
96
+ end
97
+ else
98
+ Itamae.logger.error 'serverspec_task is failed.'
99
+ exit 1
100
+ end
101
+ rescue => e
102
+ Itamae.logger.error e.inspect
103
+ Itamae.logger.info "From node file: #{node_file}"
104
+ exit 2
105
+ end
106
+ end
107
+ end
108
+ end
109
+ end
110
+ end
111
+ end
@@ -0,0 +1,3 @@
1
+ module ItamaeSpec
2
+ VERSION = File.read(File.expand_path("../version.txt", __FILE__)).strip
3
+ end
@@ -0,0 +1 @@
1
+ 0.0.2
@@ -0,0 +1,35 @@
1
+ # -*- mode: ruby -*-
2
+ # vi: set ft=ruby :
3
+ require 'vagrant-digitalocean'
4
+
5
+ # Vagrantfile API/syntax version. Don't touch unless you know what you're doing!
6
+ VAGRANTFILE_API_VERSION = "2"
7
+
8
+ Vagrant.configure(VAGRANTFILE_API_VERSION) do |config|
9
+ config.vm.define :trusty do |c|
10
+ c.vm.hostname = 'itamae-trusty'
11
+ c.vm.hostname += "-#{ENV['WERCKER_BUILD_ID']}" if ENV['WERCKER_BUILD_ID']
12
+ c.vm.provider :virtualbox do |provider, override|
13
+ override.vm.box = "ubuntu/trusty64"
14
+ override.vm.provision :shell, inline: <<-EOC
15
+ cat /etc/apt/sources.list | sed -e 's|http://[^ ]*|mirror://mirrors.ubuntu.com/mirrors.txt|g' > /tmp/sources.list
16
+ if !(diff -q /etc/apt/sources.list /tmp/sources.list); then
17
+ mv /tmp/sources.list /etc/apt/sources.list
18
+ apt-get update
19
+ fi
20
+ EOC
21
+ end
22
+
23
+ c.vm.provider :digital_ocean do |provider, override|
24
+ override.ssh.private_key_path = '~/.ssh/id_rsa.vagrant'
25
+ override.vm.box = 'digital_ocean'
26
+ override.vm.box_url = "https://github.com/smdahlen/vagrant-digitalocean/raw/master/box/digital_ocean.box"
27
+
28
+ provider.ssh_key_name = ENV['WERCKER'] ? 'vagrant/wercker/itamae' : 'Vagrant'
29
+ provider.token = ENV['DIGITALOCEAN_TOKEN']
30
+ provider.image = 'ubuntu-14-04-x64' # ubuntu
31
+ provider.region = 'nyc3'
32
+ provider.size = '512mb'
33
+ end
34
+ end
35
+ end
@@ -0,0 +1,226 @@
1
+ require 'spec_helper'
2
+
3
+ describe user("itamae") do
4
+ it { should exist }
5
+ it { should have_uid 1234 }
6
+ it { should have_home_directory '/home/itamae' }
7
+ it { should have_login_shell '/bin/dash' }
8
+ end
9
+
10
+ describe file('/tmp/included_recipe') do
11
+ it { should be_file }
12
+ end
13
+
14
+ describe package('dstat') do
15
+ it { should be_installed }
16
+ end
17
+
18
+ describe package('sl') do
19
+ it { should be_installed }
20
+ end
21
+
22
+ describe package('resolvconf') do
23
+ it { should_not be_installed }
24
+ end
25
+
26
+ %w!/tmp/remote_file /tmp/remote_file_auto!.each do |f|
27
+ describe file(f) do
28
+ it { should be_file }
29
+ its(:content) { should match(/Hello Itamae/) }
30
+ end
31
+ end
32
+
33
+ describe file('/tmp/directory') do
34
+ it { should be_directory }
35
+ it { should be_mode 700 }
36
+ it { should be_owned_by "itamae" }
37
+ it { should be_grouped_into "itamae" }
38
+ end
39
+
40
+ describe file('/tmp/directory_never_exist1') do
41
+ it { should_not be_directory }
42
+ end
43
+
44
+ %w!/tmp/template /tmp/template_auto!.each do |f|
45
+ describe file(f) do
46
+ it { should be_file }
47
+ its(:content) { should match(/Hello/) }
48
+ its(:content) { should match(/Good bye/) }
49
+ its(:content) { should match(/^total memory: \d+kB$/) }
50
+ its(:content) { should match(/^uninitialized node key: $/) }
51
+ end
52
+ end
53
+
54
+ describe file('/tmp/file') do
55
+ it { should be_file }
56
+ its(:content) { should match(/Hello World/) }
57
+ it { should be_mode 777 }
58
+ end
59
+
60
+ describe file('/tmp/execute') do
61
+ it { should be_file }
62
+ its(:content) { should match(/Hello Execute/) }
63
+ end
64
+
65
+ describe file('/tmp/never_exist1') do
66
+ it { should_not be_file }
67
+ end
68
+
69
+ describe file('/tmp/never_exist2') do
70
+ it { should_not be_file }
71
+ end
72
+
73
+ describe file('/tmp/http_request.html') do
74
+ it { should be_file }
75
+ its(:content) { should match(/"from": "itamae"/) }
76
+ end
77
+
78
+ describe file('/tmp/http_request_delete.html') do
79
+ it { should be_file }
80
+ its(:content) { should match(/"from": "itamae"/) }
81
+ end
82
+
83
+ describe file('/tmp/http_request_post.html') do
84
+ it { should be_file }
85
+ its(:content) do
86
+ should match(/"from": "itamae"/)
87
+ should match(/"love": "sushi"/)
88
+ end
89
+ end
90
+
91
+ describe file('/tmp/http_request_put.html') do
92
+ it { should be_file }
93
+ its(:content) do
94
+ should match(/"from": "itamae"/)
95
+ should match(/"love": "sushi"/)
96
+ end
97
+ end
98
+
99
+ describe file('/tmp/http_request_headers.html') do
100
+ it { should be_file }
101
+ its(:content) { should match(/"User-Agent": "Itamae"/) }
102
+ end
103
+
104
+ describe file('/tmp/http_request_redirect.html') do
105
+ it { should be_file }
106
+ its(:content) { should match(/"from": "itamae"/) }
107
+ end
108
+
109
+ describe file('/tmp/notifies') do
110
+ it { should be_file }
111
+ its(:content) { should eq("2431") }
112
+ end
113
+
114
+ describe file('/tmp/subscribes') do
115
+ it { should be_file }
116
+ its(:content) { should eq("2431") }
117
+ end
118
+
119
+ describe file('/tmp/cron_stopped') do
120
+ it { should be_file }
121
+ its(:content) do
122
+ expect(subject.content.lines.size).to eq 1
123
+ end
124
+ end
125
+
126
+ describe file('/tmp/cron_running') do
127
+ it { should be_file }
128
+ its(:content) do
129
+ expect(subject.content.lines.size).to eq 2
130
+ end
131
+ end
132
+
133
+ describe file('/tmp-link') do
134
+ it { should be_linked_to '/tmp' }
135
+ its(:content) do
136
+ expect(subject.content.lines.size).to eq 0
137
+ end
138
+ end
139
+
140
+ describe file('/tmp-link-force') do
141
+ it { should be_linked_to '/tmp' }
142
+ end
143
+
144
+ describe command('cd /tmp/git_repo && git rev-parse HEAD') do
145
+ its(:stdout) { should match(/3116e170b89dc0f7315b69c1c1e1fd7fab23ac0d/) }
146
+ end
147
+
148
+ describe command('cd /tmp/git_repo_submodule/empty_repo && cat README.md') do
149
+ its(:stdout) { should match(/Empty Repo/) }
150
+ end
151
+
152
+ describe file('/tmp/created_by_itamae_user') do
153
+ it { should be_file }
154
+ it { should be_owned_by 'itamae' }
155
+ its(:content) { should eq("/home/itamae\n/home/itamae") }
156
+ end
157
+
158
+ describe file('/tmp/created_in_default2') do
159
+ it { should be_file }
160
+ end
161
+
162
+ describe file('/tmp/never_exist3') do
163
+ it { should_not be_file }
164
+ end
165
+
166
+ describe file('/tmp/never_exist4') do
167
+ it { should_not be_file }
168
+ end
169
+
170
+ describe file('/tmp/created_in_redefine') do
171
+ it { should be_file }
172
+ its(:content) { should match(/first/) }
173
+ end
174
+
175
+ describe command('gem list') do
176
+ its(:stdout) { should include('tzinfo (1.2.2, 1.1.0)') }
177
+ end
178
+
179
+ describe command('ri Bundler') do
180
+ its(:stderr) { should eq("Nothing known about Bundler\n") }
181
+ end
182
+
183
+ describe file('/tmp/created_by_definition') do
184
+ it { should be_file }
185
+ its(:content) { should eq("name:name,key:value,message:Hello, Itamae\n") }
186
+ end
187
+
188
+ describe file('/tmp/remote_file_in_definition') do
189
+ it { should be_file }
190
+ its(:content) { should eq("definition_example\n") }
191
+ end
192
+
193
+ describe file('/tmp/multi_delayed_notifies') do
194
+ it { should be_file }
195
+ its(:content) { should eq("1\n2\n3\n4\n") }
196
+ end
197
+
198
+ describe file('/tmp/multi_immediately_notifies') do
199
+ it { should be_file }
200
+ its(:content) { should eq("1\n2\n3\n4\n") }
201
+ end
202
+
203
+ describe file('/tmp/file_edit_sample') do
204
+ it { should be_file }
205
+ its(:content) { should eq("Hello, Itamae") }
206
+ it { should be_mode 400 }
207
+ it { should be_owned_by "itamae2" }
208
+ it { should be_grouped_into "itamae2" }
209
+ end
210
+
211
+ describe file('/home/itamae2') do
212
+ it { should be_directory }
213
+ it { should be_owned_by "itamae2" }
214
+ it { should be_grouped_into "itamae2" }
215
+ end
216
+
217
+ describe file('/tmp/file_create_without_content') do
218
+ its(:content) { should eq("Hello, World") }
219
+ it { should be_mode 600 }
220
+ it { should be_owned_by "itamae" }
221
+ it { should be_grouped_into "itamae" }
222
+ end
223
+
224
+ describe file('/tmp/file_edit_notifies') do
225
+ its(:content) { should eq("1") }
226
+ end