fog-core 2.1.0 → 2.6.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (85) hide show
  1. checksums.yaml +5 -5
  2. data/.github/FUNDING.yml +2 -0
  3. data/.github/dependabot.yml +10 -0
  4. data/.github/workflows/ci.yml +32 -0
  5. data/.rubocop.yml +16 -12
  6. data/.rubocop_todo.yml +724 -0
  7. data/CONTRIBUTING.md +5 -1
  8. data/Gemfile +1 -1
  9. data/README.md +2 -1
  10. data/Rakefile +2 -14
  11. data/SECURITY.md +6 -0
  12. data/changelog.md +241 -141
  13. data/fog-core.gemspec +13 -9
  14. data/lib/fog/account.rb +0 -16
  15. data/lib/fog/billing.rb +0 -11
  16. data/lib/fog/compute/models/server.rb +7 -3
  17. data/lib/fog/compute.rb +3 -25
  18. data/lib/fog/core/association.rb +1 -0
  19. data/lib/fog/core/attributes/default.rb +7 -0
  20. data/lib/fog/core/attributes.rb +42 -5
  21. data/lib/fog/core/cache.rb +58 -55
  22. data/lib/fog/core/collection.rb +9 -3
  23. data/lib/fog/core/connection.rb +4 -6
  24. data/lib/fog/core/current_machine.rb +1 -1
  25. data/lib/fog/core/errors.rb +1 -1
  26. data/lib/fog/core/logger.rb +5 -2
  27. data/lib/fog/core/mock.rb +7 -2
  28. data/lib/fog/core/model.rb +34 -5
  29. data/lib/fog/core/provider.rb +37 -4
  30. data/lib/fog/core/scp.rb +16 -11
  31. data/lib/fog/core/service.rb +5 -5
  32. data/lib/fog/core/services_mixin.rb +62 -10
  33. data/lib/fog/core/ssh.rb +49 -25
  34. data/lib/fog/core/stringify_keys.rb +0 -2
  35. data/lib/fog/core/time.rb +2 -2
  36. data/lib/fog/core/uuid.rb +2 -8
  37. data/lib/fog/core/version.rb +3 -1
  38. data/lib/fog/core/wait_for.rb +2 -1
  39. data/lib/fog/core/wait_for_defaults.rb +2 -0
  40. data/lib/fog/core.rb +57 -59
  41. data/lib/fog/dns.rb +0 -11
  42. data/lib/fog/formatador.rb +9 -8
  43. data/lib/fog/monitoring.rb +0 -11
  44. data/lib/fog/network.rb +0 -12
  45. data/lib/fog/schema/data_validator.rb +1 -0
  46. data/lib/fog/storage.rb +15 -30
  47. data/lib/fog/support.rb +0 -12
  48. data/lib/fog/test_helpers/collection_helper.rb +2 -0
  49. data/lib/fog/test_helpers/formats_helper.rb +2 -2
  50. data/lib/fog/test_helpers/helper.rb +3 -3
  51. data/lib/fog/test_helpers/minitest/assertions.rb +1 -1
  52. data/lib/fog/test_helpers/minitest/expectations.rb +1 -1
  53. data/lib/fog/test_helpers/mock_helper.rb +84 -84
  54. data/lib/fog/test_helpers/succeeds_helper.rb +2 -2
  55. data/lib/fog/test_helpers/types_helper.rb +1 -0
  56. data/lib/fog/vpn.rb +0 -12
  57. data/lib/tasks/test_task.rb +4 -5
  58. metadata +58 -85
  59. data/.travis.yml +0 -39
  60. data/spec/compute/models/server_spec.rb +0 -229
  61. data/spec/compute_spec.rb +0 -95
  62. data/spec/connection_spec.rb +0 -105
  63. data/spec/core/cache_spec.rb +0 -191
  64. data/spec/core/model_spec.rb +0 -36
  65. data/spec/core/stringify_keys_spec.rb +0 -38
  66. data/spec/core/whitelist_keys_spec.rb +0 -36
  67. data/spec/credentials_spec.rb +0 -88
  68. data/spec/current_machine_spec.rb +0 -36
  69. data/spec/fake_app/fake_service.rb +0 -18
  70. data/spec/fake_app/models/collection.rb +0 -5
  71. data/spec/fake_app/models/model.rb +0 -2
  72. data/spec/fake_app/requests/request.rb +0 -11
  73. data/spec/fog_attribute_spec.rb +0 -549
  74. data/spec/formatador_spec.rb +0 -154
  75. data/spec/identity_spec.rb +0 -95
  76. data/spec/mocking_spec.rb +0 -84
  77. data/spec/service_spec.rb +0 -201
  78. data/spec/spec_helper.rb +0 -19
  79. data/spec/storage_spec.rb +0 -114
  80. data/spec/test_helpers/formats_helper_spec.rb +0 -121
  81. data/spec/test_helpers/schema_validator_spec.rb +0 -101
  82. data/spec/timeout_spec.rb +0 -20
  83. data/spec/utils_spec.rb +0 -29
  84. data/spec/uuid_spec.rb +0 -11
  85. data/spec/wait_for_spec.rb +0 -30
@@ -1,105 +0,0 @@
1
- require "spec_helper"
2
-
3
- describe Fog::Core::Connection do
4
- it "raises ArgumentError when no arguments given" do
5
- assert_raises(ArgumentError) do
6
- Fog::Core::Connection.new
7
- end
8
- end
9
-
10
- [:request, :reset].each do |method|
11
- it "responds to #{method}" do
12
- connection = Fog::Core::Connection.new("http://example.com")
13
- assert connection.respond_to?(method)
14
- end
15
- end
16
-
17
- it "adds custom user-agents to Fog requests" do
18
- Fog::VERSION = 'Version'
19
- Fog::Core::Connection.add_user_agent("my-app/1.2")
20
-
21
- connection = Fog::Core::Connection.new("http://example.com")
22
- assert_equal "my-app/1.2 fog/Version fog-core/#{Fog::Core::VERSION}",
23
- connection.instance_variable_get(:@excon).data[:headers]["User-Agent"]
24
-
25
- Fog.send(:remove_const, :VERSION)
26
- end
27
-
28
- it "doesn't error when persistence is enabled" do
29
- Fog::Core::Connection.new("http://example.com", true)
30
- end
31
-
32
- it "doesn't error when persistence is enabled and debug_response is disabled" do
33
- options = {
34
- :debug_response => false
35
- }
36
- Fog::Core::Connection.new("http://example.com", true, options)
37
- end
38
-
39
- describe ":path_prefix" do
40
- it "does not emit a warning when provided this argument in the initializer" do
41
- $stderr = StringIO.new
42
-
43
- Fog::Core::Connection.new("http://example.com", false, :path_prefix => "foo")
44
-
45
- assert_empty($stderr.string)
46
- end
47
-
48
- it "raises when the 'path' arg is present and this arg is supplied" do
49
- assert_raises(ArgumentError) do
50
- Fog::Core::Connection.new("http://example.com", false, :path_prefix => "foo", :path => "bar")
51
- end
52
- end
53
- end
54
-
55
- describe "#request" do
56
- describe "default behavior" do
57
- it "supplies the 'path' arg directly to Excon" do
58
- spy = Object.new
59
- spy.instance_eval do
60
- def params
61
- @params
62
- end
63
- def new(_, params)
64
- @params = params
65
- end
66
- end
67
-
68
- Object.stub_const("Excon", spy) do
69
- Fog::Core::Connection.new("http://example.com", false, :path => "bar")
70
- assert_equal("bar", spy.params[:path])
71
- end
72
- end
73
- end
74
-
75
- describe "with path_prefix supplied to the initializer" do
76
- let(:spy) do
77
- Object.new.tap do |spy|
78
- spy.instance_eval do
79
- def new(*_args); self; end
80
- def params; @params; end
81
- def request(params)
82
- @params = params
83
- end
84
- end
85
- end
86
- end
87
-
88
- it "uses the initializer-supplied :path_prefix arg with #request :arg to formulate a path to send to Excon.request" do
89
- Object.stub_const("Excon", spy) do
90
- c = Fog::Core::Connection.new("http://example.com", false, :path_prefix => "foo")
91
- c.request(:path => "bar")
92
- assert_equal("foo/bar", spy.params[:path])
93
- end
94
- end
95
-
96
- it "does not introduce consecutive '/'s into the path if 'path' starts with a '/'" do
97
- Object.stub_const("Excon", spy) do
98
- c = Fog::Core::Connection.new("http://example.com", false, :path_prefix => "foo")
99
- c.request(:path => "/bar")
100
- assert_equal("foo/bar", spy.params[:path])
101
- end
102
- end
103
- end
104
- end
105
- end
@@ -1,191 +0,0 @@
1
- require "spec_helper"
2
- require "securerandom"
3
- require "tmpdir"
4
-
5
- module Fog
6
- class SubFogTestModel < Fog::Model
7
- identity :id
8
- end
9
- end
10
-
11
- module Fog
12
- class SubFogTestService < Fog::Service
13
-
14
- class Mock
15
- attr_reader :options
16
-
17
- def initialize(opts = {})
18
- @options = opts
19
- end
20
- end
21
- end
22
- end
23
-
24
- describe Fog::Cache do
25
- before(:each) do
26
- Fog.mock!
27
- @service = Fog::SubFogTestService.new
28
- Fog::Cache.namespace_prefix = "test-dir"
29
- end
30
-
31
- it "has a namespace_prefix configurable" do
32
- Fog::Cache.namespace_prefix = "for-service-user-region-foo"
33
-
34
- # Expand path does not downcase. case insensitive platform tests.
35
- example_cache = File.expand_path(Fog::Cache.namespace(Fog::SubFogTestModel, @service)).downcase
36
- expected_namespace = File.expand_path("~/.fog-cache/for-service-user-region-foo").downcase
37
-
38
- assert_equal example_cache.include?(expected_namespace), true
39
- end
40
-
41
- it "has metadata associated to the namespace that you can save to" do
42
- Fog::Cache.clean!
43
- Fog::Cache.namespace_prefix = "for-service-user-region-foo"
44
- # nothing exists, nothing comes back
45
- assert_equal Fog::Cache.metadata, {}
46
- # write/read
47
- Fog::Cache.write_metadata({:last_dumped => "Tuesday, November 8, 2016"})
48
- assert_equal Fog::Cache.metadata[:last_dumped], "Tuesday, November 8, 2016"
49
-
50
- # diff namespace, diff metadata
51
- Fog::Cache.namespace_prefix = "different-namespace"
52
- assert_nil Fog::Cache.metadata[:last_dumped]
53
- # still accessible per namespace
54
- Fog::Cache.namespace_prefix = "for-service-user-region-foo"
55
- assert_equal Fog::Cache.metadata[:last_dumped], "Tuesday, November 8, 2016"
56
- # can overwrite
57
- Fog::Cache.write_metadata({:last_dumped => "Diff date"})
58
- assert_equal Fog::Cache.metadata[:last_dumped], "Diff date"
59
-
60
- # can't write a non-hash/data entry.
61
- assert_raises Fog::Cache::CacheDir do
62
- Fog::Cache.write_metadata("boo")
63
- end
64
-
65
- # namespace must be set as well.
66
- assert_raises Fog::Cache::CacheDir do
67
- Fog::Cache.namespace_prefix = nil
68
- Fog::Cache.write_metadata({:a => "b"})
69
- end
70
-
71
- end
72
-
73
- it "can load cache data from disk" do
74
- path = File.expand_path("~/.fog-cache-test-#{Time.now.to_i}.yml")
75
- data = "--- ok\n...\n"
76
- File.open(path, "w") { |f|
77
- f.write(data)
78
- }
79
-
80
- assert_equal "ok", Fog::Cache.load_cache(path)
81
- end
82
-
83
- it "load bad cache data - empty file, from disk" do
84
- path = File.expand_path("~/.fog-cache-test-2-#{Time.now.to_i}.yml")
85
- data = ""
86
- File.open(path, "w") { |f|
87
- f.write(data)
88
- }
89
-
90
- assert_equal false, Fog::Cache.load_cache(path)
91
- end
92
-
93
- it "must have a namespace_prefix configurable" do
94
- Fog::Cache.namespace_prefix = nil
95
- assert_raises Fog::Cache::CacheDir do
96
- Fog::Cache.load(Fog::SubFogTestModel, @service)
97
- end
98
- end
99
-
100
- it "can create a namespace" do
101
- Fog::Cache.expire_cache!(Fog::SubFogTestModel, @service)
102
- assert_equal File.exist?(Fog::Cache.namespace(Fog::SubFogTestModel, @service)), false
103
-
104
- Fog::Cache.create_namespace(Fog::SubFogTestModel, @service)
105
- assert_equal File.exist?(Fog::Cache.namespace(Fog::SubFogTestModel, @service)), true
106
- end
107
-
108
- it "will raise if no cache data found" do
109
- Fog::Cache.expire_cache!(Fog::SubFogTestModel, @service)
110
-
111
- assert_raises Fog::Cache::CacheNotFound do
112
- Fog::Cache.load(Fog::SubFogTestModel, @service)
113
- end
114
- end
115
-
116
- it "Fog cache ignores bad cache data - empty file, from disk" do
117
- Fog::Cache.expire_cache!(Fog::SubFogTestModel, @service)
118
- id = SecureRandom.hex
119
- a = Fog::SubFogTestModel.new(:id => id, :service => @service)
120
- a.cache.dump
121
-
122
- # input bad data
123
- path_dir = File.expand_path(Fog::Cache.namespace(Fog::SubFogTestModel, @service))
124
- path = File.join(path_dir, "foo.yml")
125
- data = ""
126
- File.open(path, "w") { |f|
127
- f.write(data)
128
- }
129
-
130
- assert_equal 1, Fog::Cache.load(Fog::SubFogTestModel, @service).size
131
- end
132
-
133
-
134
- it "can be dumped and reloaded back in" do
135
-
136
- Fog::Cache.expire_cache!(Fog::SubFogTestModel, @service)
137
-
138
- id = SecureRandom.hex
139
- a = Fog::SubFogTestModel.new(:id => id, :service => @service)
140
-
141
- assert_equal File.exist?(Fog::Cache.namespace(Fog::SubFogTestModel, @service)), false
142
- a.cache.dump
143
- assert_equal File.exist?(Fog::Cache.namespace(Fog::SubFogTestModel, @service)), true
144
-
145
- instances = Fog::Cache.load(Fog::SubFogTestModel, @service)
146
-
147
- assert_equal instances.first.id, a.id
148
- assert_equal instances.first.class, a.class
149
- end
150
-
151
- it "dumping two models that have a duplicate identity" do
152
- Fog::Cache.expire_cache!(Fog::SubFogTestModel, @service)
153
-
154
- id = SecureRandom.hex
155
-
156
- # security groups on aws for eg can have the same identity group name 'default'.
157
- # there are no restrictions on `identity` fog attributes to be uniq.
158
- a = Fog::SubFogTestModel.new(:id => id, :service => @service, :bar => 'bar')
159
- b = Fog::SubFogTestModel.new(:id => id, :service => @service, :foo => 'foo')
160
-
161
- a.cache.dump
162
- b.cache.dump
163
-
164
- instances = Fog::Cache.load(Fog::SubFogTestModel, @service)
165
-
166
- assert_equal instances.size, 2
167
- end
168
-
169
- it "dumping two models that have a duplicate identity twice" do
170
- Fog::Cache.expire_cache!(Fog::SubFogTestModel, @service)
171
-
172
- id = SecureRandom.hex
173
-
174
- # security groups on aws for eg can have the same identity group name 'default'.
175
- # there are no restrictions on `identity` fog attributes to be uniq.
176
- a = Fog::SubFogTestModel.new(:id => id, :service => @service, :bar => 'bar')
177
- b = Fog::SubFogTestModel.new(:id => id, :service => @service, :foo => 'foo')
178
-
179
- a.cache.dump
180
- b.cache.dump
181
-
182
- # and then again, w/out expiring cache
183
- a.cache.dump
184
- b.cache.dump
185
-
186
- instances = Fog::Cache.load(Fog::SubFogTestModel, @service)
187
-
188
- # unique-ify based on the attributes...
189
- assert_equal instances.size, 2
190
- end
191
- end
@@ -1,36 +0,0 @@
1
- require "spec_helper"
2
- require "securerandom"
3
-
4
- class FogTestModel < Fog::Model
5
- identity :id
6
- end
7
-
8
- describe Fog::Model do
9
- describe "#==" do
10
- it "is not equal if one is not a Fog::Model" do
11
- a = FogTestModel.new
12
- b = 2
13
- refute_equal a, b
14
- refute_equal b, a
15
- end
16
-
17
- it "is equal if it is the same object" do
18
- a = b = FogTestModel.new
19
- assert_equal a, b
20
- end
21
-
22
- it "is equal if it has the same non-nil identity and the same class" do
23
- id = SecureRandom.hex
24
- assert_equal FogTestModel.new(:id => id), FogTestModel.new(:id => id)
25
- end
26
-
27
- it "is not equal if both have nil identity, but are different objects" do
28
- refute_equal FogTestModel.new, FogTestModel.new
29
- end
30
-
31
- it "is not equal if it has a different identity" do
32
- refute_equal FogTestModel.new(:id => SecureRandom.hex),
33
- FogTestModel.new(:id => SecureRandom.hex)
34
- end
35
- end
36
- end
@@ -1,38 +0,0 @@
1
- require "spec_helper"
2
-
3
- describe "Fog::StringifyKeys" do
4
- describe ".stringify" do
5
- describe "when key is a Symbol" do
6
- it "replaces key with String" do
7
- input = { :key => "value" }
8
- output = Fog::StringifyKeys.stringify(input)
9
- assert(output.key?("key"))
10
- end
11
- end
12
-
13
- describe "when key is a String" do
14
- it "keeps key as String" do
15
- input = { "key" => "value" }
16
- output = Fog::StringifyKeys.stringify(input)
17
- assert(output.key?("key"))
18
- end
19
- end
20
-
21
- describe "when Hash is empty" do
22
- it "returns empty Hash" do
23
- assert_equal({}, Fog::StringifyKeys.stringify({}))
24
- end
25
- end
26
-
27
- describe "when keys are deeply nested" do
28
- it "updates only top level key" do
29
- input = { :key1 => { :key2 => { :key3 => nil }}}
30
-
31
- output = Fog::StringifyKeys.stringify(input)
32
-
33
- expected = { "key1" => { :key2 => { :key3 => nil }}}
34
- assert_equal(expected, output)
35
- end
36
- end
37
- end
38
- end
@@ -1,36 +0,0 @@
1
- require "spec_helper"
2
-
3
- describe "Fog::WhitelistKeys" do
4
- describe ".whitelist" do
5
- describe "when other keys are present" do
6
- it "returns Hash with only allowed keys" do
7
- input = { :name => "name", :type => "type", :size => 80 }
8
- valid_keys = %w(name size)
9
-
10
- output = Fog::WhitelistKeys.whitelist(input, valid_keys)
11
-
12
- expected = { "name" => "name", "size" => 80 }
13
- assert_equal(expected, output)
14
- end
15
- end
16
-
17
- describe "when key is a Symbol" do
18
- it "returns a String" do
19
- input = { :name => "name" }
20
- valid_keys = %w(name)
21
-
22
- output = Fog::WhitelistKeys.whitelist(input, valid_keys)
23
-
24
- expected = { "name" => "name" }
25
- assert(expected, output)
26
- end
27
- end
28
-
29
- describe "when Hash is empty" do
30
- it "returns empty Hash" do
31
- output = Fog::WhitelistKeys.whitelist({}, [])
32
- assert_equal({}, output)
33
- end
34
- end
35
- end
36
- end
@@ -1,88 +0,0 @@
1
- require "spec_helper"
2
-
3
- describe "credentials" do
4
- before do
5
- @old_home = ENV["HOME"]
6
- @old_rc = ENV["FOG_RC"]
7
- @old_credential = ENV["FOG_CREDENTIAL"]
8
- @old_credentials = Fog.credentials
9
- Fog.instance_variable_set("@credential_path", nil) # kill memoization
10
- Fog.instance_variable_set("@credential", nil) # kill memoization
11
- end
12
-
13
- after do
14
- ENV["HOME"] = @old_home
15
- ENV["FOG_RC"] = @old_rc
16
- ENV["FOG_CREDENTIAL"] = @old_credential
17
- Fog.credentials = @old_credentials
18
- end
19
-
20
- describe "credential" do
21
- it "returns :default for default credentials" do
22
- assert_equal :default, Fog.credential
23
- end
24
-
25
- it "returns the to_sym of the assigned value" do
26
- Fog.credential = "foo"
27
- assert_equal :foo, Fog.credential
28
- end
29
-
30
- it "can set credentials throught the FOG_CREDENTIAL env va" do
31
- ENV["FOG_CREDENTIAL"] = "bar"
32
- assert_equal :bar, Fog.credential
33
- end
34
- end
35
-
36
- describe "credentials_path" do
37
- it "has FOG_RC takes precedence over HOME" do
38
- ENV["HOME"] = "/home/path"
39
- ENV["FOG_RC"] = "/rc/path"
40
-
41
- assert_equal "/rc/path", Fog.credentials_path
42
- end
43
-
44
- it "properly expands paths" do
45
- ENV["FOG_RC"] = "/expanded/subdirectory/../path"
46
- assert_equal "/expanded/path", Fog.credentials_path
47
- end
48
-
49
- it "falls back to home path if FOG_RC not set" do
50
- ENV.delete("FOG_RC")
51
- assert_equal File.join(ENV["HOME"], ".fog"), Fog.credentials_path
52
- end
53
-
54
- it "ignores home path if it does not exist" do
55
- ENV.delete("FOG_RC")
56
- ENV["HOME"] = "/no/such/path"
57
- assert_nil Fog.credentials_path
58
- end
59
-
60
- it "File.expand_path raises because of non-absolute path" do
61
- ENV.delete("FOG_RC")
62
- ENV["HOME"] = "."
63
-
64
- if RUBY_PLATFORM == "java"
65
- Fog::Logger.warning("Stubbing out non-absolute path credentials test due to JRuby bug: https://github.com/jruby/jruby/issues/1163")
66
- else
67
- assert_nil Fog.credentials_path
68
- end
69
- end
70
-
71
- it "returns nil when neither FOG_RC or HOME are set" do
72
- ENV.delete("HOME")
73
- ENV.delete("FOG_RC")
74
- assert_nil Fog.credentials_path
75
- end
76
- end
77
-
78
- describe "symbolize_credential?" do
79
- it "returns false if the value is :headers" do
80
- refute Fog.symbolize_credential?(:headers)
81
- end
82
-
83
- it "returns true if the value is not :headers" do
84
- assert Fog.symbolize_credential?(:foo)
85
- assert Fog.symbolize_credential?(:liberate_me_ex_inheris)
86
- end
87
- end
88
- end
@@ -1,36 +0,0 @@
1
- require "spec_helper"
2
-
3
- describe Fog::CurrentMachine do
4
- before do
5
- @was_mocking = Fog.mock?
6
- Fog.mock!
7
-
8
- @old_excon_defaults_mock = Excon.defaults[:mock]
9
- Excon.defaults[:mock] = true
10
- end
11
-
12
- after do
13
- Fog.unmock! unless @was_mocking
14
-
15
- Fog::CurrentMachine.ip_address = nil
16
- Excon.stubs.clear
17
- Excon.defaults[:mock] = @old_excon_defaults_mock
18
- end
19
-
20
- describe "ip_address" do
21
- it "should be thread safe" do
22
-
23
- (1..10).map do
24
- Thread.new do
25
- Excon.stub({ :method => :get, :path => "/" }, { :body => "" })
26
- Fog::CurrentMachine.ip_address
27
- end
28
- end.each(&:join)
29
- end
30
-
31
- it "should remove trailing endline characters" do
32
- Excon.stub({ :method => :get, :path => "/" }, { :body => "192.168.0.1\n" })
33
- assert_equal "192.168.0.1", Fog::CurrentMachine.ip_address
34
- end
35
- end
36
- end
@@ -1,18 +0,0 @@
1
- class FakeService < Fog::Service
2
- class Real
3
- def initialize(_options)
4
- end
5
- end
6
-
7
- class Mock
8
- def initialize(_options)
9
- end
10
- end
11
-
12
- model_path File.join(File.dirname(__FILE__), "models")
13
- model :model
14
- collection :collection
15
-
16
- request_path File.join(File.dirname(__FILE__), "requests")
17
- request :request
18
- end
@@ -1,5 +0,0 @@
1
- require File.join(File.dirname(__FILE__), "model")
2
-
3
- class Collection < Fog::Collection
4
- model Model
5
- end
@@ -1,2 +0,0 @@
1
- class Model < Fog::Model
2
- end
@@ -1,11 +0,0 @@
1
- class FakeService < Fog::Service
2
- class Real
3
- def request
4
- end
5
- end
6
-
7
- class Mock
8
- def request
9
- end
10
- end
11
- end