From 3c78364cd2ace15ce59296bc13331776810a661a Mon Sep 17 00:00:00 2001 From: Blas Soto Date: Thu, 22 Feb 2024 15:02:47 -0300 Subject: [PATCH] [FCXPINFRA-76] Added cache for token --- Gemfile.lock | 2 + lib/little_monster.rb | 3 +- lib/little_monster/config.rb | 2 +- lib/little_monster/core.rb | 1 + lib/little_monster/tiger/auth.rb | 13 ++++- lib/little_monster/tiger/cache.rb | 27 ++++++++++ little_monster.gemspec | 1 + spec/lib/little_monster/tiger/api_spec.rb | 58 ++++++++++++++++++++ spec/lib/little_monster/tiger/cache_spec.rb | 59 +++++++++++++++++++++ spec/mock/responses/tiger_token.json | 2 +- 10 files changed, 164 insertions(+), 4 deletions(-) create mode 100644 lib/little_monster/tiger/cache.rb create mode 100644 spec/lib/little_monster/tiger/cache_spec.rb diff --git a/Gemfile.lock b/Gemfile.lock index f709189..fa8c381 100644 --- a/Gemfile.lock +++ b/Gemfile.lock @@ -3,6 +3,7 @@ PATH specs: little_monster (0.1.30) activesupport (= 6.1.7.6) + moneta (= 1.6.0) multi_json (= 1.15.0) thor (= 1.2.1) tilt (= 2.1.0) @@ -112,6 +113,7 @@ GEM jwt (2.7.1) method_source (1.0.0) minitest (5.22.2) + moneta (1.6.0) multi_json (1.15.0) newrelic_rpm (9.0.0) oj (3.14.2) diff --git a/lib/little_monster.rb b/lib/little_monster.rb index 6c32a8e..e8a0b43 100644 --- a/lib/little_monster.rb +++ b/lib/little_monster.rb @@ -53,7 +53,8 @@ def default_config_values heartbeat_execution_interval: 10, default_job_retries: -1, tiger_api_url: 'http://tiger', - shark_login_file_path: '/var/run/secrets/kubernetes.io/serviceaccount/token' + shark_login_file_path: '/var/run/secrets/kubernetes.io/serviceaccount/token', + enable_tiger_token: true } end diff --git a/lib/little_monster/config.rb b/lib/little_monster/config.rb index 6df1a87..e827fe5 100644 --- a/lib/little_monster/config.rb +++ b/lib/little_monster/config.rb @@ -3,7 +3,7 @@ class Config attr_accessor :api_url, :worker_concurrency, :worker_queue, :worker_provider, :formatter, :request_timeout, :default_request_retries, :default_request_retry_wait, :task_requests_retries, :task_requests_retry_wait, :job_requests_retries, :job_requests_retry_wait, :heartbeat_execution_interval, :default_job_retries, - :tiger_api_url, :shark_login_file_path + :tiger_api_url, :shark_login_file_path, :enable_tiger_token def initialize(params = {}) params.to_hash.each do |key, value| diff --git a/lib/little_monster/core.rb b/lib/little_monster/core.rb index c893dc9..3eb2fc8 100644 --- a/lib/little_monster/core.rb +++ b/lib/little_monster/core.rb @@ -13,6 +13,7 @@ require 'little_monster/core/errors/task_not_found_error' require 'little_monster/tiger/auth' +require 'little_monster/tiger/cache' require 'little_monster/core/tagged_logger' require 'little_monster/core/loggable' # must be required first to satisfy job and task dependencies require 'little_monster/core/api' diff --git a/lib/little_monster/tiger/auth.rb b/lib/little_monster/tiger/auth.rb index b1d4fae..776b50f 100644 --- a/lib/little_monster/tiger/auth.rb +++ b/lib/little_monster/tiger/auth.rb @@ -7,11 +7,22 @@ module API module_function def bearer_token - token = new_shark_token + token = cached_shark_token "Bearer #{token}" if token end + def cached_shark_token + shark_token = Cache.instance.get(:shark_token) + return shark_token if shark_token + + shark_token = new_shark_token + return nil if shark_token.nil? + Cache.instance.set(:shark_token, shark_token, 60 * 60) + shark_token + end + def new_shark_token + return nil unless LittleMonster.enable_tiger_token shark_token = File.read(LittleMonster.shark_login_file_path) response = make_call(:post, 'login/shark', body: { token: shark_token }.to_json) return nil if response.failure? diff --git a/lib/little_monster/tiger/cache.rb b/lib/little_monster/tiger/cache.rb new file mode 100644 index 0000000..d98fd9d --- /dev/null +++ b/lib/little_monster/tiger/cache.rb @@ -0,0 +1,27 @@ +require 'moneta' + +module LittleMonster + module Tiger + class Cache + include Singleton + + attr_reader :cache + + def initialize + @cache = Moneta.new(:Memory, expires: true) + end + + def set(key, value, expires = 0) + @cache.store(key, value, expires: expires) + end + + def get(key) + @cache[key] + end + + def clear + @cache.clear + end + end + end +end diff --git a/little_monster.gemspec b/little_monster.gemspec index 5def746..421f9e8 100644 --- a/little_monster.gemspec +++ b/little_monster.gemspec @@ -32,6 +32,7 @@ Gem::Specification.new do |spec| spec.add_runtime_dependency 'tilt', '2.1.0' spec.add_runtime_dependency 'toiler', '0.7.1' spec.add_runtime_dependency 'typhoeus', '1.4.0' + spec.add_runtime_dependency 'moneta', '1.6.0' spec.add_development_dependency 'bundler' spec.add_development_dependency 'byebug', '11.1.3' diff --git a/spec/lib/little_monster/tiger/api_spec.rb b/spec/lib/little_monster/tiger/api_spec.rb index e9f847b..5400504 100644 --- a/spec/lib/little_monster/tiger/api_spec.rb +++ b/spec/lib/little_monster/tiger/api_spec.rb @@ -4,6 +4,7 @@ subject(:api) { described_class } before do + LittleMonster::Tiger::Cache.instance.cache.clear allow(File).to receive(:read).with(LittleMonster.shark_login_file_path).and_return('') end @@ -32,6 +33,63 @@ end end + describe '.cached_shark_token' do + context 'when the shark login success' do + let(:body_str) { File.open('./spec/mock/responses/tiger_token.json', 'r').read } + let(:body) { JSON.parse(body_str) } + + before do + LoginSharkMock.new(self).login_request_success(body_str) + end + + it 'return correct token' do + expect(api.cached_shark_token).to eq(body['token']) + end + end + + context 'when the shark login fail' do + before do + LoginSharkMock.new(self).login_request_failure + end + + it 'return nil' do + expect(api.cached_shark_token).to be_nil + end + end + + context 'when called cached_shark_token the next call' do + let(:body_str) { File.open('./spec/mock/responses/tiger_token.json', 'r').read } + let(:body) { JSON.parse(body_str) } + + before do + LoginSharkMock.new(self).login_request_success(body_str) + api.cached_shark_token + allow(Typhoeus::Request).to receive(:new).and_call_original + end + + it 'dont request to login endpoint' do + + api.cached_shark_token + expect(Typhoeus::Request).not_to have_received(:new) + end + end + + context 'when called cached_shark_token for first time' do + let(:body_str) { File.open('./spec/mock/responses/tiger_token.json', 'r').read } + let(:body) { JSON.parse(body_str) } + + before do + LoginSharkMock.new(self).login_request_success(body_str) + allow(Typhoeus::Request).to receive(:new).and_call_original + end + + it 'request to login endpoint' do + api.cached_shark_token + expect(Typhoeus::Request).to have_received(:new) + end + end + end + describe '.new_shark_token' do context 'when the shark login success' do let(:body_str) { File.open('./spec/mock/responses/tiger_token.json', 'r').read } diff --git a/spec/lib/little_monster/tiger/cache_spec.rb b/spec/lib/little_monster/tiger/cache_spec.rb new file mode 100644 index 0000000..d8ba9bc --- /dev/null +++ b/spec/lib/little_monster/tiger/cache_spec.rb @@ -0,0 +1,59 @@ +require 'spec_helper' + +describe LittleMonster::Tiger::Cache do + subject(:cache) { described_class } + + let(:key) { SecureRandom.uuid } + + before do + LittleMonster::Tiger::Cache.instance.cache.clear + cache.instance.set(:key, key) + end + + describe '.set' do + context 'when set a key and value' do + before do + cache.instance.set(:key, key) + end + + it 'store that value for that key' do + expect(cache.instance.get(:key)).to eq(key) + end + end + + context 'when set a key, value and expires' do + let(:expires) { 1 } + + before do + cache.instance.set(:key, key, expires) + end + + it 'store that value for that key for `expires` seconds' do + expect(cache.instance.get(:key)).to eq(key) + Kernel.sleep(expires + 1) + expect(cache.instance.get(:key)).to be_nil + end + end + end + + describe '.get' do + context 'when get from a not exist key' do + it 'return nil' do + expect(cache.instance.get(:foo)).to be_nil + end + end + end + + describe '.clear' do + context 'when get a exist key after clear cache' do + + before do + LittleMonster::Tiger::Cache.instance.cache.clear + end + + it 'return nil' do + expect(cache.instance.get(:key)).to be_nil + end + end + end +end diff --git a/spec/mock/responses/tiger_token.json b/spec/mock/responses/tiger_token.json index f182272..11f99ba 100644 --- a/spec/mock/responses/tiger_token.json +++ b/spec/mock/responses/tiger_token.json @@ -1,3 +1,3 @@ { - "token": "eyJhbGciOiJSUzI1NiIsImtpZCI6ImFkNGYyMWRkLTgwZTItNGY2ZC1iOGY0LWE4OTE2ZDY0YTFhZiIsInR5cCI6IkpXVCJ9.eyJhZGRpdGlvbmFsX2luZm8iOnsiZW1haWwiOiJleGFtcGxlIiwiZnVsbF9uYW1lIjoiZXhhbXBsZSIsInVzZXJuYW1lIjoiZXhhbXBsZSJ9LCJleHAiOjQ3OTM4NzEyNzUsImlhdCI6MTY0MDI3MTI3NSwiaWRlbnRpdHkiOiJtcm46c2VnaW5mOmFkOnVzZXIvZXhhbXBsZSIsImlzcyI6ImZ1cnlfdGlnZXIiLCJzdWIiOiJleGFtcGxlIn0.OsfqgNjn52j_xxMRKNssDJQIgdVU4yVWVDnisI6yRGDyYw-hQ2-WnaHN9e5Obwpy6E0WDtdnt4Hk8nzk4QvMSQ" + "token": "foo" }