kuby-core 0.7.2 → 0.10.0
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/CHANGELOG.md +42 -0
- data/Gemfile +1 -0
- data/README.md +11 -1
- data/bin/kuby +4 -0
- data/kuby-core.gemspec +9 -4
- data/lib/kuby.rb +58 -19
- data/lib/kuby/basic_logger.rb +13 -0
- data/lib/kuby/cli_base.rb +81 -8
- data/lib/kuby/commands.rb +244 -0
- data/lib/kuby/definition.rb +1 -11
- data/lib/kuby/dev_setup.rb +255 -0
- data/lib/kuby/docker.rb +1 -0
- data/lib/kuby/docker/bundler_phase.rb +3 -3
- data/lib/kuby/docker/cli.rb +13 -1
- data/lib/kuby/docker/dev_spec.rb +131 -0
- data/lib/kuby/docker/dockerfile.rb +16 -1
- data/lib/kuby/docker/layer.rb +4 -4
- data/lib/kuby/docker/layer_stack.rb +4 -0
- data/lib/kuby/docker/local_tags.rb +4 -0
- data/lib/kuby/docker/metadata.rb +18 -38
- data/lib/kuby/docker/package_phase.rb +2 -2
- data/lib/kuby/docker/setup_phase.rb +3 -2
- data/lib/kuby/docker/spec.rb +42 -16
- data/lib/kuby/docker/timestamp_tag.rb +6 -0
- data/lib/kuby/environment.rb +15 -2
- data/lib/kuby/kubernetes.rb +9 -11
- data/lib/kuby/kubernetes/deploy_task.rb +4 -1
- data/lib/kuby/kubernetes/deployer.rb +70 -15
- data/lib/kuby/kubernetes/{minikube_provider.rb → docker_desktop_provider.rb} +8 -4
- data/lib/kuby/kubernetes/provider.rb +12 -8
- data/lib/kuby/kubernetes/spec.rb +30 -29
- data/lib/kuby/plugin.rb +59 -0
- data/lib/kuby/plugin_registry.rb +27 -0
- data/lib/kuby/plugins.rb +6 -0
- data/lib/kuby/plugins/nginx_ingress.rb +71 -0
- data/lib/kuby/plugins/rails_app.rb +18 -0
- data/lib/kuby/plugins/rails_app/asset_copy_task.rb +117 -0
- data/lib/kuby/plugins/rails_app/assets.rb +347 -0
- data/lib/kuby/plugins/rails_app/database.rb +74 -0
- data/lib/kuby/{kubernetes/plugins → plugins}/rails_app/generators/kuby.rb +14 -16
- data/lib/kuby/plugins/rails_app/mysql.rb +152 -0
- data/lib/kuby/plugins/rails_app/plugin.rb +593 -0
- data/lib/kuby/plugins/rails_app/postgres.rb +143 -0
- data/lib/kuby/plugins/rails_app/rewrite_db_config.rb +11 -0
- data/lib/kuby/plugins/rails_app/sqlite.rb +32 -0
- data/lib/kuby/plugins/rails_app/tasks.rake +36 -0
- data/lib/kuby/rails_commands.rb +89 -0
- data/lib/kuby/railtie.rb +0 -4
- data/lib/kuby/tasks.rb +85 -31
- data/lib/kuby/version.rb +1 -1
- data/spec/docker/metadata_spec.rb +84 -0
- data/spec/docker/spec_spec.rb +266 -0
- data/spec/docker/timestamp_tag_spec.rb +54 -4
- data/spec/dummy/Gemfile +54 -0
- data/spec/dummy/Gemfile.lock +223 -0
- data/spec/dummy/README.md +24 -0
- data/spec/dummy/Rakefile +6 -0
- data/spec/dummy/app/assets/config/manifest.js +2 -0
- data/spec/dummy/app/assets/stylesheets/application.css +15 -0
- data/spec/dummy/app/channels/application_cable/channel.rb +4 -0
- data/spec/dummy/app/channels/application_cable/connection.rb +4 -0
- data/spec/dummy/app/controllers/application_controller.rb +2 -0
- data/spec/dummy/app/helpers/application_helper.rb +2 -0
- data/spec/dummy/app/javascript/channels/consumer.js +6 -0
- data/spec/dummy/app/javascript/channels/index.js +5 -0
- data/spec/dummy/app/javascript/packs/application.js +17 -0
- data/spec/dummy/app/jobs/application_job.rb +7 -0
- data/spec/dummy/app/mailers/application_mailer.rb +4 -0
- data/spec/dummy/app/models/application_record.rb +3 -0
- data/spec/dummy/app/views/layouts/application.html.erb +15 -0
- data/spec/dummy/app/views/layouts/mailer.html.erb +13 -0
- data/spec/dummy/app/views/layouts/mailer.text.erb +1 -0
- data/spec/dummy/bin/bundle +114 -0
- data/spec/dummy/bin/rails +9 -0
- data/spec/dummy/bin/rake +9 -0
- data/spec/dummy/bin/setup +36 -0
- data/spec/dummy/bin/spring +17 -0
- data/spec/dummy/bin/yarn +11 -0
- data/spec/dummy/config.ru +5 -0
- data/spec/dummy/config/application.rb +19 -0
- data/spec/dummy/config/boot.rb +4 -0
- data/spec/dummy/config/cable.yml +10 -0
- data/spec/dummy/config/credentials.yml.enc +1 -0
- data/spec/dummy/config/database.yml +25 -0
- data/spec/dummy/config/environment.rb +5 -0
- data/spec/dummy/config/environments/development.rb +62 -0
- data/spec/dummy/config/environments/production.rb +112 -0
- data/spec/dummy/config/environments/test.rb +49 -0
- data/spec/dummy/config/initializers/application_controller_renderer.rb +8 -0
- data/spec/dummy/config/initializers/assets.rb +14 -0
- data/spec/dummy/config/initializers/backtrace_silencers.rb +7 -0
- data/spec/dummy/config/initializers/content_security_policy.rb +30 -0
- data/spec/dummy/config/initializers/cookies_serializer.rb +5 -0
- data/spec/dummy/config/initializers/filter_parameter_logging.rb +4 -0
- data/spec/dummy/config/initializers/inflections.rb +16 -0
- data/spec/dummy/config/initializers/mime_types.rb +4 -0
- data/spec/dummy/config/initializers/wrap_parameters.rb +14 -0
- data/spec/dummy/config/locales/en.yml +33 -0
- data/spec/dummy/config/master.key +1 -0
- data/spec/dummy/config/puma.rb +38 -0
- data/spec/dummy/config/routes.rb +3 -0
- data/spec/dummy/config/spring.rb +6 -0
- data/spec/dummy/config/storage.yml +34 -0
- data/spec/dummy/db/seeds.rb +7 -0
- data/spec/dummy/package.json +11 -0
- data/spec/dummy/public/404.html +67 -0
- data/spec/dummy/public/422.html +67 -0
- data/spec/dummy/public/500.html +66 -0
- data/spec/dummy/public/apple-touch-icon-precomposed.png +0 -0
- data/spec/dummy/public/apple-touch-icon.png +0 -0
- data/spec/dummy/public/favicon.ico +0 -0
- data/spec/dummy/public/robots.txt +1 -0
- data/spec/dummy/test/application_system_test_case.rb +5 -0
- data/spec/dummy/test/channels/application_cable/connection_test.rb +11 -0
- data/spec/dummy/test/test_helper.rb +13 -0
- data/spec/dummy/tmp/cache/bootsnap-load-path-cache +0 -0
- data/spec/spec_helper.rb +77 -2
- data/spec/support/docker/fake_cli.rb +54 -0
- data/spec/support/docker/remote/fake_client.rb +16 -0
- data/spec/trailing_hash_spec.rb +23 -0
- metadata +139 -30
- data/lib/ext/krane/kubernetes_resource.rb +0 -16
- data/lib/kuby/kubernetes/plugin.rb +0 -55
- data/lib/kuby/kubernetes/plugins.rb +0 -8
- data/lib/kuby/kubernetes/plugins/nginx_ingress.rb +0 -73
- data/lib/kuby/kubernetes/plugins/rails_app.rb +0 -16
- data/lib/kuby/kubernetes/plugins/rails_app/database.rb +0 -79
- data/lib/kuby/kubernetes/plugins/rails_app/mysql.rb +0 -154
- data/lib/kuby/kubernetes/plugins/rails_app/plugin.rb +0 -379
- data/lib/kuby/kubernetes/plugins/rails_app/postgres.rb +0 -142
- data/lib/kuby/kubernetes/plugins/rails_app/rewrite_db_config.rb +0 -13
- data/lib/kuby/kubernetes/plugins/rails_app/sqlite.rb +0 -30
- data/lib/kuby/kubernetes/plugins/rails_app/tasks.rake +0 -28
- data/lib/kuby/tasks/kuby.rake +0 -70
data/lib/kuby/version.rb
CHANGED
@@ -0,0 +1,84 @@
|
|
1
|
+
require 'spec_helper'
|
2
|
+
require 'timecop'
|
3
|
+
|
4
|
+
describe Kuby::Docker::Metadata do
|
5
|
+
let(:metadata) { definition.environment.docker.metadata }
|
6
|
+
|
7
|
+
describe '#image_url' do
|
8
|
+
subject { metadata.image_url }
|
9
|
+
|
10
|
+
it { is_expected.to eq(docker_image_url) }
|
11
|
+
|
12
|
+
context 'when no image URL is configured' do
|
13
|
+
let(:docker_image_url) { nil }
|
14
|
+
it { is_expected.to eq(definition.app_name) }
|
15
|
+
end
|
16
|
+
end
|
17
|
+
|
18
|
+
describe '#image_host' do
|
19
|
+
subject { metadata.image_host }
|
20
|
+
|
21
|
+
it { is_expected.to eq(described_class::DEFAULT_REGISTRY_HOST) }
|
22
|
+
|
23
|
+
context 'when the image URL contains an explicit host' do
|
24
|
+
let(:docker_image_url) { 'registry.foo.com/foo/testapp' }
|
25
|
+
|
26
|
+
it { is_expected.to eq('https://registry.foo.com') }
|
27
|
+
end
|
28
|
+
|
29
|
+
context 'when the image URL contains an explicit host with scheme' do
|
30
|
+
let(:docker_image_url) { 'http://registry.foo.com/foo/testapp' }
|
31
|
+
|
32
|
+
it { is_expected.to eq('http://registry.foo.com') }
|
33
|
+
end
|
34
|
+
end
|
35
|
+
|
36
|
+
describe '#image_repo' do
|
37
|
+
subject { metadata.image_repo }
|
38
|
+
|
39
|
+
it { is_expected.to eq('foo/testapp') }
|
40
|
+
|
41
|
+
context 'when the image URL contains an explicit host' do
|
42
|
+
let(:docker_image_url) { 'registry.foo.com/foo/testapp' }
|
43
|
+
|
44
|
+
it { is_expected.to eq('foo/testapp') }
|
45
|
+
end
|
46
|
+
end
|
47
|
+
|
48
|
+
describe '#image_hostname' do
|
49
|
+
subject { metadata.image_hostname }
|
50
|
+
|
51
|
+
it { is_expected.to eq('www.docker.com') }
|
52
|
+
|
53
|
+
context 'when the image URL contains an explicit host' do
|
54
|
+
let(:docker_image_url) { 'registry.foo.com/foo/testapp' }
|
55
|
+
|
56
|
+
it { is_expected.to eq('registry.foo.com') }
|
57
|
+
end
|
58
|
+
end
|
59
|
+
|
60
|
+
describe '#tags' do
|
61
|
+
subject { metadata.tags }
|
62
|
+
|
63
|
+
it 'specifies the current timestamp tag and the default tag' do
|
64
|
+
Timecop.freeze do
|
65
|
+
expect(subject).to eq([
|
66
|
+
Time.now.strftime('%Y%m%d%H%M%S'),
|
67
|
+
Kuby::Docker::Metadata::LATEST_TAG
|
68
|
+
])
|
69
|
+
end
|
70
|
+
end
|
71
|
+
end
|
72
|
+
|
73
|
+
describe '#distro' do
|
74
|
+
subject { metadata.distro }
|
75
|
+
|
76
|
+
it { is_expected.to eq(Kuby::Docker::Metadata::DEFAULT_DISTRO) }
|
77
|
+
|
78
|
+
context 'with a distro set manually' do
|
79
|
+
before { metadata.distro = :alpine }
|
80
|
+
|
81
|
+
it { is_expected.to eq(:alpine) }
|
82
|
+
end
|
83
|
+
end
|
84
|
+
end
|
@@ -0,0 +1,266 @@
|
|
1
|
+
require 'spec_helper'
|
2
|
+
require 'timecop'
|
3
|
+
|
4
|
+
describe Kuby::Docker::Spec do
|
5
|
+
let(:spec) { definition.environment.docker }
|
6
|
+
|
7
|
+
describe '#base_image' do
|
8
|
+
subject { spec.to_dockerfile.to_s }
|
9
|
+
|
10
|
+
it 'uses the default base image for Debian' do
|
11
|
+
expect(subject).to include("FROM ruby:#{RUBY_VERSION}\n")
|
12
|
+
end
|
13
|
+
|
14
|
+
context 'when the distro is set to Alpine' do
|
15
|
+
before { spec.distro(:alpine) }
|
16
|
+
|
17
|
+
it 'uses the Alpine base image' do
|
18
|
+
expect(subject).to include("FROM ruby:#{RUBY_VERSION}-alpine\n")
|
19
|
+
end
|
20
|
+
end
|
21
|
+
|
22
|
+
context 'when the base image is set to something custom' do
|
23
|
+
before { spec.base_image('foo/bar') }
|
24
|
+
|
25
|
+
it 'uses the base image as given' do
|
26
|
+
expect(subject).to include("FROM foo/bar\n")
|
27
|
+
end
|
28
|
+
end
|
29
|
+
end
|
30
|
+
|
31
|
+
describe '#working_dir' do
|
32
|
+
let(:default_working_dir) do
|
33
|
+
Kuby::Docker::SetupPhase::DEFAULT_WORKING_DIR
|
34
|
+
end
|
35
|
+
|
36
|
+
subject { spec.to_dockerfile.to_s }
|
37
|
+
|
38
|
+
it 'uses the default working dir' do
|
39
|
+
expect(subject).to(
|
40
|
+
include("WORKDIR #{default_working_dir}\n")
|
41
|
+
)
|
42
|
+
end
|
43
|
+
|
44
|
+
context 'when the working dir is set to something custom' do
|
45
|
+
before { spec.working_dir('/foo/bar') }
|
46
|
+
|
47
|
+
it 'uses the working dir as given' do
|
48
|
+
expect(subject).to include("WORKDIR /foo/bar\n")
|
49
|
+
end
|
50
|
+
end
|
51
|
+
end
|
52
|
+
|
53
|
+
describe '#rails_env' do
|
54
|
+
subject { spec.to_dockerfile.to_s }
|
55
|
+
|
56
|
+
it 'uses the name of the current Kuby environment' do
|
57
|
+
expect(subject).to include("ENV RAILS_ENV=#{spec.environment.name}\n")
|
58
|
+
expect(subject).to include("ENV KUBY_ENV=#{spec.environment.name}\n")
|
59
|
+
end
|
60
|
+
|
61
|
+
context 'when the environment is set to something custom' do
|
62
|
+
before { spec.rails_env('foobar') }
|
63
|
+
|
64
|
+
it 'uses the environment as given' do
|
65
|
+
expect(subject).to include("ENV RAILS_ENV=foobar\n")
|
66
|
+
end
|
67
|
+
|
68
|
+
it "doesn't change the Kuby env" do
|
69
|
+
expect(subject).to include("ENV KUBY_ENV=#{spec.environment.name}\n")
|
70
|
+
end
|
71
|
+
end
|
72
|
+
end
|
73
|
+
|
74
|
+
describe '#bundler_version' do
|
75
|
+
subject { spec.to_dockerfile.to_s }
|
76
|
+
|
77
|
+
it 'installs the current bundler version' do
|
78
|
+
expect(subject).to(
|
79
|
+
include("RUN gem install bundler -v #{Bundler::VERSION}\n")
|
80
|
+
)
|
81
|
+
end
|
82
|
+
|
83
|
+
context 'when the bundler version is set to something custom' do
|
84
|
+
before { spec.bundler_version('1.17.3') }
|
85
|
+
|
86
|
+
it 'installs the given version' do
|
87
|
+
expect(subject).to include("RUN gem install bundler -v 1.17.3\n")
|
88
|
+
end
|
89
|
+
end
|
90
|
+
end
|
91
|
+
|
92
|
+
describe '#gemfile' do
|
93
|
+
subject { spec.to_dockerfile.to_s }
|
94
|
+
|
95
|
+
it 'uses the default Gemfile' do
|
96
|
+
expect(subject).to include("COPY Gemfile .\n")
|
97
|
+
expect(subject).to include("COPY Gemfile.lock .\n")
|
98
|
+
expect(subject).to match(/RUN bundle install .* --gemfile Gemfile/)
|
99
|
+
end
|
100
|
+
|
101
|
+
context 'when the gemfile path is set to something custom' do
|
102
|
+
before { spec.gemfile('foo/bar/Gemfile') }
|
103
|
+
|
104
|
+
it 'uses the given gemfile' do
|
105
|
+
expect(subject).to include("COPY foo/bar/Gemfile .\n")
|
106
|
+
expect(subject).to include("COPY foo/bar/Gemfile.lock .\n")
|
107
|
+
expect(subject).to match(/RUN bundle install .* --gemfile foo\/bar\/Gemfile/)
|
108
|
+
end
|
109
|
+
end
|
110
|
+
end
|
111
|
+
|
112
|
+
describe '#package' do
|
113
|
+
subject { spec.to_dockerfile.to_s }
|
114
|
+
|
115
|
+
it 'installs the given package' do
|
116
|
+
# configured in spec_helper.rb
|
117
|
+
spec.package(:fake_package)
|
118
|
+
|
119
|
+
expect(subject).to match(/apt-get install .* fake_package/m)
|
120
|
+
end
|
121
|
+
end
|
122
|
+
|
123
|
+
describe '#files' do
|
124
|
+
subject { spec.to_dockerfile.to_s }
|
125
|
+
|
126
|
+
it 'copies the current directory contents by default' do
|
127
|
+
expect(subject).to include("COPY ./ .\n")
|
128
|
+
end
|
129
|
+
|
130
|
+
context 'when given a custom path to copy' do
|
131
|
+
before { spec.files('./foo/bar') }
|
132
|
+
|
133
|
+
it 'copies the given paths only' do
|
134
|
+
expect(subject).to include("COPY ./foo/bar .\n")
|
135
|
+
end
|
136
|
+
end
|
137
|
+
end
|
138
|
+
|
139
|
+
describe '#port' do
|
140
|
+
let(:default_port) do
|
141
|
+
Kuby::Docker::WebserverPhase::DEFAULT_PORT
|
142
|
+
end
|
143
|
+
|
144
|
+
subject { spec.to_dockerfile.to_s }
|
145
|
+
|
146
|
+
it 'exposes the default port' do
|
147
|
+
expect(subject).to include("EXPOSE #{default_port}\n")
|
148
|
+
end
|
149
|
+
|
150
|
+
context 'when given a custom port' do
|
151
|
+
before { spec.port(5555) }
|
152
|
+
|
153
|
+
it 'exposes the given port' do
|
154
|
+
expect(subject).to include("EXPOSE 5555\n")
|
155
|
+
end
|
156
|
+
end
|
157
|
+
end
|
158
|
+
|
159
|
+
describe '#tag' do
|
160
|
+
let(:tag) { make_ts_tag(Time.now) }
|
161
|
+
|
162
|
+
subject { spec.tag }
|
163
|
+
|
164
|
+
context 'with no local or remote tags' do
|
165
|
+
it 'raises an error' do
|
166
|
+
expect { subject }.to raise_error(Kuby::Docker::MissingTagError)
|
167
|
+
end
|
168
|
+
end
|
169
|
+
|
170
|
+
context 'with an available remote tag' do
|
171
|
+
before { docker_remote_client.tags << tag }
|
172
|
+
|
173
|
+
it { is_expected.to eq(tag) }
|
174
|
+
end
|
175
|
+
|
176
|
+
context 'with an available local tag' do
|
177
|
+
before do
|
178
|
+
docker_cli.build(
|
179
|
+
dockerfile: nil,
|
180
|
+
image_url: docker_image_url,
|
181
|
+
tags: [tag]
|
182
|
+
)
|
183
|
+
end
|
184
|
+
|
185
|
+
it { is_expected.to eq(tag) }
|
186
|
+
end
|
187
|
+
|
188
|
+
context 'with multiple remote tags' do
|
189
|
+
let(:time) { Time.now }
|
190
|
+
|
191
|
+
before do
|
192
|
+
docker_remote_client.tags +=
|
193
|
+
[time - 5, time + 10, time - 10, time + 15].map do |t|
|
194
|
+
make_ts_tag(t)
|
195
|
+
end
|
196
|
+
end
|
197
|
+
|
198
|
+
it { is_expected.to eq(make_ts_tag(time + 15)) }
|
199
|
+
end
|
200
|
+
|
201
|
+
context 'with multiple local and remote tags' do
|
202
|
+
let(:time) { Time.now }
|
203
|
+
|
204
|
+
before do
|
205
|
+
docker_remote_client.tags +=
|
206
|
+
[time - 5, time + 10, time - 10, time + 15].map do |t|
|
207
|
+
make_ts_tag(t)
|
208
|
+
end
|
209
|
+
|
210
|
+
docker_cli.build(
|
211
|
+
dockerfile: nil,
|
212
|
+
image_url: docker_image_url,
|
213
|
+
tags: [time - 3, time + 6, time - 6, time + 18].map do |t|
|
214
|
+
make_ts_tag(t)
|
215
|
+
end
|
216
|
+
)
|
217
|
+
end
|
218
|
+
|
219
|
+
it { is_expected.to eq(make_ts_tag(time + 18)) }
|
220
|
+
end
|
221
|
+
end
|
222
|
+
|
223
|
+
describe '#previous_tag' do
|
224
|
+
let(:time) { Time.now }
|
225
|
+
let(:current_tag) { make_ts_tag(time) }
|
226
|
+
|
227
|
+
before do
|
228
|
+
docker_remote_client.tags << current_tag
|
229
|
+
docker_cli.build(
|
230
|
+
dockerfile: nil,
|
231
|
+
image_url: docker_image_url,
|
232
|
+
tags: [current_tag]
|
233
|
+
)
|
234
|
+
end
|
235
|
+
|
236
|
+
subject { spec.previous_tag(current_tag) }
|
237
|
+
|
238
|
+
context 'with no previous local or remote tag' do
|
239
|
+
it 'raises an error' do
|
240
|
+
expect { subject }.to raise_error(Kuby::Docker::MissingTagError)
|
241
|
+
end
|
242
|
+
end
|
243
|
+
|
244
|
+
context 'with an available previous remote tag' do
|
245
|
+
let(:previous_tag) { make_ts_tag(time - 5) }
|
246
|
+
|
247
|
+
before { docker_remote_client.tags << previous_tag }
|
248
|
+
|
249
|
+
it { is_expected.to eq(previous_tag) }
|
250
|
+
end
|
251
|
+
|
252
|
+
context 'with an available previous local tag' do
|
253
|
+
let(:previous_tag) { make_ts_tag(time - 5) }
|
254
|
+
|
255
|
+
before do
|
256
|
+
docker_cli.build(
|
257
|
+
dockerfile: nil,
|
258
|
+
image_url: docker_image_url,
|
259
|
+
tags: [previous_tag]
|
260
|
+
)
|
261
|
+
end
|
262
|
+
|
263
|
+
it { is_expected.to eq(previous_tag) }
|
264
|
+
end
|
265
|
+
end
|
266
|
+
end
|
@@ -1,11 +1,61 @@
|
|
1
1
|
require "spec_helper"
|
2
2
|
|
3
3
|
describe Kuby::Docker::TimestampTag do
|
4
|
-
context
|
5
|
-
|
6
|
-
tag = described_class.try_parse("20200810165134")
|
4
|
+
context '.try_parse' do
|
5
|
+
let(:tag_str) { '20200810165134' }
|
7
6
|
|
8
|
-
|
7
|
+
it 'creates a new timestamp tag' do
|
8
|
+
tag = described_class.try_parse(tag_str)
|
9
|
+
expect(tag).to be_a(described_class)
|
10
|
+
end
|
11
|
+
|
12
|
+
it 'correctly parses the timestamp contained in the tag' do
|
13
|
+
time = described_class.try_parse(tag_str).time
|
14
|
+
expect([time.year, time.month, time.day, time.hour, time.min, time.sec]).to(
|
15
|
+
eq([2020, 8, 10, 16, 51, 34])
|
16
|
+
)
|
17
|
+
end
|
18
|
+
|
19
|
+
context 'with an invalid tag' do
|
20
|
+
let(:tag_str) { 'abc123' }
|
21
|
+
|
22
|
+
it 'returns nil' do
|
23
|
+
expect(described_class.try_parse(tag_str)).to eq(nil)
|
24
|
+
end
|
25
|
+
end
|
26
|
+
end
|
27
|
+
|
28
|
+
context '#to_s' do
|
29
|
+
it 'serializes the tag as a timestamp' do
|
30
|
+
tag = described_class.new(Time.new(2020, 8, 10, 16, 51, 34))
|
31
|
+
expect(tag.to_s).to eq('20200810165134')
|
32
|
+
end
|
33
|
+
end
|
34
|
+
|
35
|
+
context 'comparison' do
|
36
|
+
it 'ensures tags can be compared by their timestamp values' do
|
37
|
+
seed_time = Time.now
|
38
|
+
times = [seed_time, seed_time + 5, seed_time + 10, seed_time + 15].shuffle
|
39
|
+
tags = times.map { |t| described_class.new(t) }
|
40
|
+
expect(tags.sort.map(&:time)).to eq(times.sort)
|
41
|
+
end
|
42
|
+
end
|
43
|
+
|
44
|
+
context 'equality' do
|
45
|
+
it 'ensures tags with equal times are considered equal' do
|
46
|
+
time = Time.now
|
47
|
+
tag1 = described_class.new(time)
|
48
|
+
tag2 = described_class.new(time)
|
49
|
+
expect(tag1).to eq(tag2)
|
50
|
+
expect(tag1.hash).to eq(tag2.hash)
|
51
|
+
end
|
52
|
+
|
53
|
+
it 'ensures tags with inequal times are not considered equal' do
|
54
|
+
time = Time.now
|
55
|
+
tag1 = described_class.new(time)
|
56
|
+
tag2 = described_class.new(time + 5)
|
57
|
+
expect(tag1).to_not eq(tag2)
|
58
|
+
expect(tag1.hash).to_not eq(tag2.hash)
|
9
59
|
end
|
10
60
|
end
|
11
61
|
end
|
data/spec/dummy/Gemfile
ADDED
@@ -0,0 +1,54 @@
|
|
1
|
+
source 'https://rubygems.org'
|
2
|
+
git_source(:github) { |repo| "https://github.com/#{repo}.git" }
|
3
|
+
|
4
|
+
ruby '2.5.8'
|
5
|
+
|
6
|
+
# Bundle edge Rails instead: gem 'rails', github: 'rails/rails'
|
7
|
+
gem 'rails', '~> 6.0.3', '>= 6.0.3.2'
|
8
|
+
# Use sqlite3 as the database for Active Record
|
9
|
+
gem 'sqlite3', '~> 1.4'
|
10
|
+
# Use Puma as the app server
|
11
|
+
gem 'puma', '~> 4.1'
|
12
|
+
# Use SCSS for stylesheets
|
13
|
+
gem 'sass-rails', '>= 6'
|
14
|
+
# Transpile app-like JavaScript. Read more: https://github.com/rails/webpacker
|
15
|
+
gem 'webpacker', '~> 4.0'
|
16
|
+
# Turbolinks makes navigating your web application faster. Read more: https://github.com/turbolinks/turbolinks
|
17
|
+
gem 'turbolinks', '~> 5'
|
18
|
+
# Build JSON APIs with ease. Read more: https://github.com/rails/jbuilder
|
19
|
+
gem 'jbuilder', '~> 2.7'
|
20
|
+
# Use Redis adapter to run Action Cable in production
|
21
|
+
# gem 'redis', '~> 4.0'
|
22
|
+
# Use Active Model has_secure_password
|
23
|
+
# gem 'bcrypt', '~> 3.1.7'
|
24
|
+
|
25
|
+
# Use Active Storage variant
|
26
|
+
# gem 'image_processing', '~> 1.2'
|
27
|
+
|
28
|
+
# Reduces boot times through caching; required in config/boot.rb
|
29
|
+
gem 'bootsnap', '>= 1.4.2', require: false
|
30
|
+
|
31
|
+
group :development, :test do
|
32
|
+
# Call 'byebug' anywhere in the code to stop execution and get a debugger console
|
33
|
+
gem 'byebug', platforms: [:mri, :mingw, :x64_mingw]
|
34
|
+
end
|
35
|
+
|
36
|
+
group :development do
|
37
|
+
# Access an interactive console on exception pages or by calling 'console' anywhere in the code.
|
38
|
+
gem 'web-console', '>= 3.3.0'
|
39
|
+
gem 'listen', '~> 3.2'
|
40
|
+
# Spring speeds up development by keeping your application running in the background. Read more: https://github.com/rails/spring
|
41
|
+
gem 'spring'
|
42
|
+
gem 'spring-watcher-listen', '~> 2.0.0'
|
43
|
+
end
|
44
|
+
|
45
|
+
group :test do
|
46
|
+
# Adds support for Capybara system testing and selenium driver
|
47
|
+
gem 'capybara', '>= 2.15'
|
48
|
+
gem 'selenium-webdriver'
|
49
|
+
# Easy installation and use of web drivers to run system tests with browsers
|
50
|
+
gem 'webdrivers'
|
51
|
+
end
|
52
|
+
|
53
|
+
# Windows does not include zoneinfo files, so bundle the tzinfo-data gem
|
54
|
+
gem 'tzinfo-data', platforms: [:mingw, :mswin, :x64_mingw, :jruby]
|