nucleus 0.1.0 → 0.2.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 (39) hide show
  1. checksums.yaml +4 -4
  2. data/.rubocop.yml +3 -0
  3. data/CHANGELOG.md +18 -4
  4. data/README.md +28 -40
  5. data/Rakefile +137 -137
  6. data/config/nucleus_config.rb +0 -4
  7. data/lib/nucleus/adapter_resolver.rb +115 -115
  8. data/lib/nucleus/adapters/buildpack_translator.rb +79 -79
  9. data/lib/nucleus/adapters/v1/cloud_control/application.rb +108 -108
  10. data/lib/nucleus/adapters/v1/cloud_control/authentication.rb +27 -27
  11. data/lib/nucleus/adapters/v1/cloud_control/cloud_control.rb +153 -153
  12. data/lib/nucleus/adapters/v1/cloud_control/domains.rb +68 -68
  13. data/lib/nucleus/adapters/v1/cloud_control/logs.rb +103 -103
  14. data/lib/nucleus/adapters/v1/cloud_control/vars.rb +88 -88
  15. data/lib/nucleus/adapters/v1/cloud_foundry_v2/domains.rb +149 -149
  16. data/lib/nucleus/adapters/v1/cloud_foundry_v2/logs.rb +303 -303
  17. data/lib/nucleus/adapters/v1/cloud_foundry_v2/services.rb +286 -286
  18. data/lib/nucleus/adapters/v1/heroku/heroku.rb +2 -2
  19. data/lib/nucleus/adapters/v1/heroku/logs.rb +108 -108
  20. data/lib/nucleus/core/adapter_authentication_inductor.rb +0 -2
  21. data/lib/nucleus/core/adapter_extensions/auth/http_basic_auth_client.rb +37 -37
  22. data/lib/nucleus/core/adapter_extensions/http_client.rb +177 -177
  23. data/lib/nucleus/core/common/files/archive_extractor.rb +112 -112
  24. data/lib/nucleus/core/common/files/archiver.rb +91 -91
  25. data/lib/nucleus/core/common/logging/request_log_formatter.rb +48 -48
  26. data/lib/nucleus/core/error_messages.rb +127 -127
  27. data/lib/nucleus/core/models/abstract_model.rb +29 -29
  28. data/lib/nucleus/scripts/load_dependencies.rb +0 -1
  29. data/lib/nucleus/scripts/setup_config.rb +28 -28
  30. data/lib/nucleus/version.rb +3 -3
  31. data/nucleus.gemspec +10 -12
  32. data/spec/factories/models.rb +63 -61
  33. data/spec/integration/api/auth_spec.rb +58 -58
  34. data/spec/test_suites.rake +31 -31
  35. data/spec/unit/common/helpers/auth_helper_spec.rb +73 -73
  36. data/spec/unit/common/oauth2_auth_client_spec.rb +1 -1
  37. data/tasks/compatibility.rake +113 -113
  38. data/tasks/evaluation.rake +162 -162
  39. metadata +16 -30
@@ -1,58 +1,58 @@
1
- require 'spec/integration/integration_spec_helper'
2
-
3
- describe Nucleus::API::V1::Auth do
4
- after { Nucleus::TestDataGenerator.clean }
5
-
6
- let!(:vendor_a) { create(:vendor) }
7
- let!(:vendor_b) { create(:vendor) }
8
- let!(:provider_a) { create(:provider, vendor: vendor_a.id) }
9
- let!(:provider_b) { create(:provider, vendor: vendor_b.id) }
10
- let!(:endpoint_a) { create(:endpoint, provider: provider_a.id) }
11
- let!(:endpoint_b) { create(:endpoint, provider: provider_b.id) }
12
- let!(:adapter_a) { create(:adapter, id: endpoint_a.id, adapter_clazz: Nucleus::Adapters::V1::Heroku) }
13
- let!(:adapter_b) { create(:adapter, id: endpoint_b.id, adapter_clazz: Nucleus::Adapters::V1::CloudFoundryV2) }
14
-
15
- # tests case when 'use RequestStore::Middleware' was not applied
16
- context 'With alternating endpoint requests' do
17
- before do
18
- allow_any_instance_of(Nucleus::Adapters::V1::Heroku).to receive(:auth_client) do
19
- token_auth = double(Nucleus::Adapters::TokenAuthClient)
20
- allow(token_auth).to receive(:authenticate) { token_auth }
21
- allow(token_auth).to receive(:auth_header) { { 'Authorization' => 'bearer 1234567890' } }
22
- token_auth
23
- end
24
- allow_any_instance_of(Nucleus::Adapters::V1::CloudFoundryV2).to receive(:auth_client) do
25
- oauth = double(Nucleus::Adapters::OAuth2AuthClient)
26
- allow(oauth).to receive(:authenticate) { oauth }
27
- allow(oauth).to receive(:auth_header) { { 'Authorization' => 'bearer 0987654321' } }
28
- allow(oauth).to receive(:refresh) { oauth }
29
- oauth
30
- end
31
-
32
- allow_any_instance_of(Nucleus::Adapters::V1::Heroku).to receive(:applications).and_wrap_original do |m, _|
33
- unless m.receiver.send(:headers)['Authorization'] == 'bearer 1234567890'
34
- fail Nucleus::Errors::EndpointAuthenticationError, 'Bad authentication credentials'
35
- end
36
- []
37
- end
38
- call_count = 0
39
- allow_any_instance_of(Nucleus::Adapters::V1::CloudFoundryV2).to receive(:applications).and_wrap_original do |m, _|
40
- unless m.receiver.send(:headers)['Authorization'] == 'bearer 0987654321'
41
- fail Nucleus::Errors::EndpointAuthenticationError, 'Bad authentication credentials'
42
- end
43
- call_count += 1
44
- fail Nucleus::Errors::EndpointAuthenticationError, 'Fail 1st attempt' if call_count == 1
45
- []
46
- end
47
- end
48
- it 'credentials are not re-used for different requests' do
49
- headers_a = { 'HTTP_AUTHORIZATION' => 'Basic ' + ['username_a:password_a'].pack('m*').gsub(/\n/, '') }
50
- get "/endpoints/#{endpoint_a.id}/applications", headers_a
51
- expect(response.status).to eq(200)
52
-
53
- headers_b = { 'HTTP_AUTHORIZATION' => 'Basic ' + ['username_b:password_b'].pack('m*').gsub(/\n/, '') }
54
- get "/endpoints/#{endpoint_b.id}/applications", headers_b
55
- expect(response.status).to eq(200)
56
- end
57
- end
58
- end
1
+ require 'spec/integration/integration_spec_helper'
2
+
3
+ describe Nucleus::API::V1::Auth do
4
+ after { Nucleus::TestDataGenerator.clean }
5
+
6
+ let!(:vendor_a) { create(:vendor) }
7
+ let!(:vendor_b) { create(:vendor) }
8
+ let!(:provider_a) { create(:provider, vendor: vendor_a.id) }
9
+ let!(:provider_b) { create(:provider, vendor: vendor_b.id) }
10
+ let!(:endpoint_a) { create(:endpoint, provider: provider_a.id) }
11
+ let!(:endpoint_b) { create(:endpoint, provider: provider_b.id) }
12
+ let!(:adapter_a) { create(:adapter, id: endpoint_a.id, adapter_clazz: Nucleus::Adapters::V1::Heroku) }
13
+ let!(:adapter_b) { create(:adapter, id: endpoint_b.id, adapter_clazz: Nucleus::Adapters::V1::CloudFoundryV2) }
14
+
15
+ # tests case when 'use RequestStore::Middleware' was not applied
16
+ context 'With alternating endpoint requests' do
17
+ before do
18
+ allow_any_instance_of(Nucleus::Adapters::V1::Heroku).to receive(:auth_client) do
19
+ token_auth = double(Nucleus::Adapters::TokenAuthClient)
20
+ allow(token_auth).to receive(:authenticate) { token_auth }
21
+ allow(token_auth).to receive(:auth_header) { { 'Authorization' => 'bearer 1234567890' } }
22
+ token_auth
23
+ end
24
+ allow_any_instance_of(Nucleus::Adapters::V1::CloudFoundryV2).to receive(:auth_client) do
25
+ oauth = double(Nucleus::Adapters::OAuth2AuthClient)
26
+ allow(oauth).to receive(:authenticate) { oauth }
27
+ allow(oauth).to receive(:auth_header) { { 'Authorization' => 'bearer 0987654321' } }
28
+ allow(oauth).to receive(:refresh) { oauth }
29
+ oauth
30
+ end
31
+
32
+ allow_any_instance_of(Nucleus::Adapters::V1::Heroku).to receive(:applications).and_wrap_original do |m, _|
33
+ unless m.receiver.send(:headers)['Authorization'] == 'bearer 1234567890'
34
+ fail Nucleus::Errors::EndpointAuthenticationError, 'Bad authentication credentials'
35
+ end
36
+ []
37
+ end
38
+ call_count = 0
39
+ allow_any_instance_of(Nucleus::Adapters::V1::CloudFoundryV2).to receive(:applications).and_wrap_original do |m, _|
40
+ unless m.receiver.send(:headers)['Authorization'] == 'bearer 0987654321'
41
+ fail Nucleus::Errors::EndpointAuthenticationError, 'Bad authentication credentials'
42
+ end
43
+ call_count += 1
44
+ fail Nucleus::Errors::EndpointAuthenticationError, 'Fail 1st attempt' if call_count == 1
45
+ []
46
+ end
47
+ end
48
+ it 'credentials are not re-used for different requests' do
49
+ headers_a = { 'HTTP_AUTHORIZATION' => 'Basic ' + ['username_a:password_a'].pack('m*').delete("\n") }
50
+ get "/endpoints/#{endpoint_a.id}/applications", headers_a
51
+ expect(response.status).to eq(200)
52
+
53
+ headers_b = { 'HTTP_AUTHORIZATION' => 'Basic ' + ['username_b:password_b'].pack('m*').delete("\n") }
54
+ get "/endpoints/#{endpoint_b.id}/applications", headers_b
55
+ expect(response.status).to eq(200)
56
+ end
57
+ end
58
+ end
@@ -1,31 +1,31 @@
1
- require 'rspec/core/rake_task'
2
-
3
- SPEC_SUITES = [
4
- { id: :unit, title: 'unit tests', pattern: 'spec/unit/**/*_spec.rb' },
5
- { id: :adapters, title: 'adapter tests', pattern: 'spec/adapter/**/*_spec.rb' },
6
- { id: :integration, title: 'integration tests', pattern: 'spec/integration/**/*_spec.rb' }
7
- ]
8
-
9
- namespace :spec do
10
- namespace :suite do
11
- SPEC_SUITES.each do |suite|
12
- desc "Run all specs in #{suite[:title]} spec suite"
13
- RSpec::Core::RakeTask.new(suite[:id]) do |t|
14
- t.pattern = suite[:pattern]
15
- t.verbose = false
16
- t.fail_on_error = false
17
- end
18
- end
19
- desc 'Run all spec suites'
20
- task :all do
21
- require 'English'
22
- failed = []
23
- SPEC_SUITES.each do |suite|
24
- p "Running spec suite #{suite[:id]} ..."
25
- Rake::Task["spec:suite:#{suite[:id]}"].execute
26
- failed << suite[:id] unless $CHILD_STATUS.success?
27
- end
28
- fail "Spec suite#{failed.length > 1 ? 's' : ''} '#{failed.join(', ')}' failed" unless failed.empty?
29
- end
30
- end
31
- end
1
+ require 'rspec/core/rake_task'
2
+
3
+ SPEC_SUITES = [
4
+ { id: :unit, title: 'unit tests', pattern: 'spec/unit/**/*_spec.rb' },
5
+ { id: :adapters, title: 'adapter tests', pattern: 'spec/adapter/**/*_spec.rb' },
6
+ { id: :integration, title: 'integration tests', pattern: 'spec/integration/**/*_spec.rb' }
7
+ ].freeze
8
+
9
+ namespace :spec do
10
+ namespace :suite do
11
+ SPEC_SUITES.each do |suite|
12
+ desc "Run all specs in #{suite[:title]} spec suite"
13
+ RSpec::Core::RakeTask.new(suite[:id]) do |t|
14
+ t.pattern = suite[:pattern]
15
+ t.verbose = false
16
+ t.fail_on_error = false
17
+ end
18
+ end
19
+ desc 'Run all spec suites'
20
+ task :all do
21
+ require 'English'
22
+ failed = []
23
+ SPEC_SUITES.each do |suite|
24
+ p "Running spec suite #{suite[:id]} ..."
25
+ Rake::Task["spec:suite:#{suite[:id]}"].execute
26
+ failed << suite[:id] unless $CHILD_STATUS.success?
27
+ end
28
+ fail "Spec suite#{failed.length > 1 ? 's' : ''} '#{failed.join(', ')}' failed" unless failed.empty?
29
+ end
30
+ end
31
+ end
@@ -1,73 +1,73 @@
1
- require 'spec_helper'
2
-
3
- describe Nucleus::Adapters::AuthenticationRetryWrapper do
4
- let!(:adapter) { double('adapter') }
5
- let!(:auth_client) { double('auth_client') }
6
- let!(:calculator) { double('calculator') }
7
- let!(:user) { 'my fictionary user' }
8
- let!(:pass) { 'my fictionary password' }
9
- let!(:fake_env) { { 'HTTP_AUTHORIZATION' => 'Basic ' + ["#{user}:#{pass}"].pack('m*').gsub(/\n/, '') } }
10
- before do
11
- cache_key = 'a unique cache key!'
12
- cache_dao = double(Nucleus::API::DB::CacheDao)
13
- allow(cache_dao).to receive(:get) do |key|
14
- key.end_with?('adapter') ? adapter : cache_key
15
- end
16
- RequestStore.store[:cache_key] = cache_key
17
- allow(adapter).to receive(:cache)
18
- allow(adapter).to receive(:cache_key)
19
- allow(adapter).to receive(:cached) { auth_client }
20
- end
21
-
22
- describe '#with_authentication' do
23
- context 'when cache is outdated' do
24
- before do
25
- counted = 0
26
- expect = 1
27
- allow(calculator).to receive(:calc) do
28
- fail(Nucleus::Errors::EndpointAuthenticationError.new('error', auth_client)) if (counted += 1) <= expect
29
- 1
30
- end
31
- end
32
-
33
- context 'and refresh was ok' do
34
- it 'response is returned in repeated call' do
35
- expect(auth_client).to receive(:refresh).once
36
- expect(calculator).to receive(:calc).exactly(2).times
37
- Nucleus::Adapters::AuthenticationRetryWrapper.with_authentication(adapter, fake_env) { calculator.calc }
38
- end
39
- end
40
- context 'and refresh failed' do
41
- before do
42
- allow(auth_client).to receive(:refresh).and_raise(
43
- Nucleus::Errors::EndpointAuthenticationError.new('error', auth_client))
44
- end
45
- context 'but authentication succeeded' do
46
- before { allow(adapter).to receive(:authenticate) { 'authentication result' } }
47
- it 'response is returned in repeated call after the authentication' do
48
- expect(auth_client).to receive(:authenticate).once
49
- expect(calculator).to receive(:calc).exactly(2).times
50
- Nucleus::Adapters::AuthenticationRetryWrapper.with_authentication(adapter, fake_env) { calculator.calc }
51
- end
52
- end
53
- context 'and authentication failed' do
54
- it 'finally fails' do
55
- expect(auth_client).to receive(:authenticate).once.and_raise(Nucleus::Errors::EndpointAuthenticationError,
56
- 'error')
57
- expect(calculator).to receive(:calc).exactly(1).times
58
- expect do
59
- Nucleus::Adapters::AuthenticationRetryWrapper.with_authentication(adapter, fake_env) { calculator.calc }
60
- end.to raise_error(Nucleus::Errors::EndpointAuthenticationError)
61
- end
62
- end
63
- end
64
- end
65
- end
66
-
67
- describe '#re_authenticate' do
68
- it 'calls authentication on the adapter' do
69
- expect(auth_client).to receive(:authenticate).once.with(user, pass)
70
- Nucleus::Adapters::AuthenticationRetryWrapper.re_authenticate(adapter, fake_env)
71
- end
72
- end
73
- end
1
+ require 'spec_helper'
2
+
3
+ describe Nucleus::Adapters::AuthenticationRetryWrapper do
4
+ let!(:adapter) { double('adapter') }
5
+ let!(:auth_client) { double('auth_client') }
6
+ let!(:calculator) { double('calculator') }
7
+ let!(:user) { 'my fictionary user' }
8
+ let!(:pass) { 'my fictionary password' }
9
+ let!(:fake_env) { { 'HTTP_AUTHORIZATION' => 'Basic ' + ["#{user}:#{pass}"].pack('m*').delete("\n") } }
10
+ before do
11
+ cache_key = 'a unique cache key!'
12
+ cache_dao = double(Nucleus::API::DB::CacheDao)
13
+ allow(cache_dao).to receive(:get) do |key|
14
+ key.end_with?('adapter') ? adapter : cache_key
15
+ end
16
+ RequestStore.store[:cache_key] = cache_key
17
+ allow(adapter).to receive(:cache)
18
+ allow(adapter).to receive(:cache_key)
19
+ allow(adapter).to receive(:cached) { auth_client }
20
+ end
21
+
22
+ describe '#with_authentication' do
23
+ context 'when cache is outdated' do
24
+ before do
25
+ counted = 0
26
+ expect = 1
27
+ allow(calculator).to receive(:calc) do
28
+ fail(Nucleus::Errors::EndpointAuthenticationError.new('error', auth_client)) if (counted += 1) <= expect
29
+ 1
30
+ end
31
+ end
32
+
33
+ context 'and refresh was ok' do
34
+ it 'response is returned in repeated call' do
35
+ expect(auth_client).to receive(:refresh).once
36
+ expect(calculator).to receive(:calc).exactly(2).times
37
+ Nucleus::Adapters::AuthenticationRetryWrapper.with_authentication(adapter, fake_env) { calculator.calc }
38
+ end
39
+ end
40
+ context 'and refresh failed' do
41
+ before do
42
+ allow(auth_client).to receive(:refresh).and_raise(
43
+ Nucleus::Errors::EndpointAuthenticationError.new('error', auth_client))
44
+ end
45
+ context 'but authentication succeeded' do
46
+ before { allow(adapter).to receive(:authenticate) { 'authentication result' } }
47
+ it 'response is returned in repeated call after the authentication' do
48
+ expect(auth_client).to receive(:authenticate).once
49
+ expect(calculator).to receive(:calc).exactly(2).times
50
+ Nucleus::Adapters::AuthenticationRetryWrapper.with_authentication(adapter, fake_env) { calculator.calc }
51
+ end
52
+ end
53
+ context 'and authentication failed' do
54
+ it 'finally fails' do
55
+ expect(auth_client).to receive(:authenticate).once.and_raise(Nucleus::Errors::EndpointAuthenticationError,
56
+ 'error')
57
+ expect(calculator).to receive(:calc).exactly(1).times
58
+ expect do
59
+ Nucleus::Adapters::AuthenticationRetryWrapper.with_authentication(adapter, fake_env) { calculator.calc }
60
+ end.to raise_error(Nucleus::Errors::EndpointAuthenticationError)
61
+ end
62
+ end
63
+ end
64
+ end
65
+ end
66
+
67
+ describe '#re_authenticate' do
68
+ it 'calls authentication on the adapter' do
69
+ expect(auth_client).to receive(:authenticate).once.with(user, pass)
70
+ Nucleus::Adapters::AuthenticationRetryWrapper.re_authenticate(adapter, fake_env)
71
+ end
72
+ end
73
+ end
@@ -6,7 +6,7 @@ describe Nucleus::Adapters::OAuth2AuthClient do
6
6
  url = 'theurl'
7
7
  check_certs = false
8
8
  client = Nucleus::Adapters::OAuth2AuthClient.new url, check_certs
9
- expect(client.instance_variable_get :@auth_url).to be url
9
+ expect(client.instance_variable_get(:@auth_url)).to be url
10
10
  expect(client.verify_ssl).to be check_certs
11
11
  end
12
12
  end
@@ -1,113 +1,113 @@
1
- require 'rspec/core/rake_task'
2
-
3
- namespace :evaluation do
4
- namespace :compatibility do
5
- task load: :environment do
6
- # TODO: choose API version
7
- api_version = 'v1'
8
- stub = Nucleus::Adapters.const_get(api_version.upcase).const_get('Stub').new 'https://api.example.org'
9
-
10
- adapter_dao = Nucleus::API::DB::AdapterDao.instance(api_version)
11
- endpoint_dao = Nucleus::API::DB::EndpointDao.instance(api_version)
12
- provider_dao = Nucleus::API::DB::ProviderDao.instance(api_version)
13
- vendor_dao = Nucleus::API::DB::VendorDao.instance(api_version)
14
- @vendor_results = {}
15
-
16
- adapter_dao.all.each do |adapter_index_entry|
17
- vendor_name = vendor_dao.get(provider_dao.get(endpoint_dao.get(adapter_index_entry.id).provider).vendor).name
18
- next if @vendor_results.key?(vendor_name)
19
- adapter_results = {}
20
- adapter = adapter_index_entry.adapter_clazz.new('https://api.example.org', 'http://apps.example.org', true)
21
- stub.public_methods(false).each do |method_name|
22
- args = []
23
- method = stub.method(method_name)
24
- method.arity.times { |time| args.push(time) }
25
- begin
26
- adapter.send(method_name, *args)
27
- implemented = true
28
- rescue Nucleus::Errors::AdapterMissingImplementationError
29
- implemented = false
30
- rescue StandardError
31
- implemented = true
32
- end
33
- adapter_results[method_name] = implemented
34
- end
35
- @vendor_results[vendor_name] = adapter_results
36
- end
37
- end
38
-
39
- task markdown: :load do
40
- # table header
41
- puts "Method / Vendor|#{@vendor_results.keys.join('|')}"
42
-
43
- # column styles
44
- alignment = ':--'
45
- @vendor_results.length.times { |_time| alignment << '|:-:' }
46
- puts alignment
47
-
48
- lines = []
49
- @vendor_results.each do |_vendor, results|
50
- results.each_with_index do |(method, supported), line|
51
- lines[line] = "#{method}" unless lines[line]
52
- lines[line] << "|#{supported ? '&#10003;' : '&#10007;'}"
53
- end
54
- end
55
-
56
- lines.each do |line|
57
- puts line
58
- end
59
- end
60
-
61
- task :latex, [:save_to] => :load do |_t, args|
62
- all_lines = []
63
- all_lines << "\\begin{longtable}{|L{7cm}|#{'c|' * @vendor_results.length}}"
64
- next_line = ' \\multicolumn{1}{l}{\\Large{\\textbf{Adapter compatibility}}}'
65
- @vendor_results.keys.each do |vendor|
66
- next_line += " & \\multicolumn{1}{l}{\\turn{60}{#{vendor}}}"
67
- end
68
- next_line += ' \\\\\\hline'
69
- all_lines << next_line
70
- all_lines << ' \\endhead'
71
- all_lines << ' \\rowcolor{white}'
72
- all_lines << ' \\caption{List of methods that are supported by Nucleus per vendor}'\
73
- '\\label{table:evaluation_adapter_compatibility}%'
74
- all_lines << ' \\endlastfoot'
75
-
76
- lines = []
77
- @vendor_results.each do |_vendor, results|
78
- results.each_with_index do |(method, supported), line|
79
- lines[line] = "#{method}" unless lines[line]
80
- lines[line] << " & #{supported ? '\\ding{51}' : '\\cellcolor{failedtablebg}\\ding{55}'}"
81
- end
82
- end
83
-
84
- # format and print all lines
85
- lines.each_with_index do |line, index|
86
- if index != lines.length - 1
87
- all_lines << " #{line.gsub(/_/, '\_')} \\\\\\hline"
88
- else
89
- # special treatment for the last line
90
- all_lines << " #{line.gsub(/_/, '\_')} \\\\\\hhline{|=|#{'=|' * @vendor_results.length}}"
91
- end
92
- end
93
-
94
- # print general statistics
95
- total_methods = @vendor_results.collect { |_v, tests| tests.length }.uniq.first
96
- supported_count = @vendor_results.collect { |_v, tests| tests.find_all { |_m, s| s }.length }
97
- all_lines << " Supported methods & #{supported_count.join(' & ')} \\\\\\hline"
98
- to_print = supported_count.collect do |supported|
99
- "#{format('%g', format('%.1f', (supported / total_methods.to_f * 100)))} \\%"
100
- end
101
-
102
- all_lines << " Supported degree & #{to_print.join(' & ')} \\\\\\hline"
103
-
104
- all_lines << '\\end{longtable}'
105
-
106
- # print lines
107
- all_lines.each { |line| puts line }
108
-
109
- # and save to file if requested
110
- File.open(args.save_to, 'w') { |file| file.write all_lines.join("\n") } if args.save_to
111
- end
112
- end
113
- end
1
+ require 'rspec/core/rake_task'
2
+
3
+ namespace :evaluation do
4
+ namespace :compatibility do
5
+ task load: :environment do
6
+ # TODO: choose API version
7
+ api_version = 'v1'
8
+ stub = Nucleus::Adapters.const_get(api_version.upcase).const_get('Stub').new 'https://api.example.org'
9
+
10
+ adapter_dao = Nucleus::API::DB::AdapterDao.instance(api_version)
11
+ endpoint_dao = Nucleus::API::DB::EndpointDao.instance(api_version)
12
+ provider_dao = Nucleus::API::DB::ProviderDao.instance(api_version)
13
+ vendor_dao = Nucleus::API::DB::VendorDao.instance(api_version)
14
+ @vendor_results = {}
15
+
16
+ adapter_dao.all.each do |adapter_index_entry|
17
+ vendor_name = vendor_dao.get(provider_dao.get(endpoint_dao.get(adapter_index_entry.id).provider).vendor).name
18
+ next if @vendor_results.key?(vendor_name)
19
+ adapter_results = {}
20
+ adapter = adapter_index_entry.adapter_clazz.new('https://api.example.org', 'http://apps.example.org', true)
21
+ stub.public_methods(false).each do |method_name|
22
+ args = []
23
+ method = stub.method(method_name)
24
+ method.arity.times { |time| args.push(time) }
25
+ begin
26
+ adapter.send(method_name, *args)
27
+ implemented = true
28
+ rescue Nucleus::Errors::AdapterMissingImplementationError
29
+ implemented = false
30
+ rescue StandardError
31
+ implemented = true
32
+ end
33
+ adapter_results[method_name] = implemented
34
+ end
35
+ @vendor_results[vendor_name] = adapter_results
36
+ end
37
+ end
38
+
39
+ task markdown: :load do
40
+ # table header
41
+ puts "Method / Vendor|#{@vendor_results.keys.join('|')}"
42
+
43
+ # column styles
44
+ alignment = ':--'
45
+ @vendor_results.length.times { |_time| alignment << '|:-:' }
46
+ puts alignment
47
+
48
+ lines = []
49
+ @vendor_results.each do |_vendor, results|
50
+ results.each_with_index do |(method, supported), line|
51
+ lines[line] = method.to_s unless lines[line]
52
+ lines[line] << "|#{supported ? '&#10003;' : '&#10007;'}"
53
+ end
54
+ end
55
+
56
+ lines.each do |line|
57
+ puts line
58
+ end
59
+ end
60
+
61
+ task :latex, [:save_to] => :load do |_t, args|
62
+ all_lines = []
63
+ all_lines << "\\begin{longtable}{|L{7cm}|#{'c|' * @vendor_results.length}}"
64
+ next_line = ' \\multicolumn{1}{l}{\\Large{\\textbf{Adapter compatibility}}}'
65
+ @vendor_results.keys.each do |vendor|
66
+ next_line += " & \\multicolumn{1}{l}{\\turn{60}{#{vendor}}}"
67
+ end
68
+ next_line += ' \\\\\\hline'
69
+ all_lines << next_line
70
+ all_lines << ' \\endhead'
71
+ all_lines << ' \\rowcolor{white}'
72
+ all_lines << ' \\caption{List of methods that are supported by Nucleus per vendor}'\
73
+ '\\label{table:evaluation_adapter_compatibility}%'
74
+ all_lines << ' \\endlastfoot'
75
+
76
+ lines = []
77
+ @vendor_results.each do |_vendor, results|
78
+ results.each_with_index do |(method, supported), line|
79
+ lines[line] = method.to_s unless lines[line]
80
+ lines[line] << " & #{supported ? '\\ding{51}' : '\\cellcolor{failedtablebg}\\ding{55}'}"
81
+ end
82
+ end
83
+
84
+ # format and print all lines
85
+ lines.each_with_index do |line, index|
86
+ all_lines << if index != lines.length - 1
87
+ " #{line.gsub(/_/, '\_')} \\\\\\hline"
88
+ else
89
+ # special treatment for the last line
90
+ " #{line.gsub(/_/, '\_')} \\\\\\hhline{|=|#{'=|' * @vendor_results.length}}"
91
+ end
92
+ end
93
+
94
+ # print general statistics
95
+ total_methods = @vendor_results.collect { |_v, tests| tests.length }.uniq.first
96
+ supported_count = @vendor_results.collect { |_v, tests| tests.find_all { |_m, s| s }.length }
97
+ all_lines << " Supported methods & #{supported_count.join(' & ')} \\\\\\hline"
98
+ to_print = supported_count.collect do |supported|
99
+ "#{format('%g', format('%.1f', (supported / total_methods.to_f * 100)))} \\%"
100
+ end
101
+
102
+ all_lines << " Supported degree & #{to_print.join(' & ')} \\\\\\hline"
103
+
104
+ all_lines << '\\end{longtable}'
105
+
106
+ # print lines
107
+ all_lines.each { |line| puts line }
108
+
109
+ # and save to file if requested
110
+ File.open(args.save_to, 'w') { |file| file.write all_lines.join("\n") } if args.save_to
111
+ end
112
+ end
113
+ end