From c4ea7cdae6ba6de0fc0dd74d7dabdc36195a55d0 Mon Sep 17 00:00:00 2001 From: Ryan Lue Date: Mon, 15 Apr 2019 19:39:20 +0800 Subject: [PATCH] Refactoring: Migrate user_device_test to RSpec --- spec/models/user_device_spec.rb | 222 +++++++++++++++++++++ spec/support/negated_matchers.rb | 1 + test/unit/user_device_test.rb | 332 ------------------------------- 3 files changed, 223 insertions(+), 332 deletions(-) create mode 100644 spec/models/user_device_spec.rb delete mode 100644 test/unit/user_device_test.rb diff --git a/spec/models/user_device_spec.rb b/spec/models/user_device_spec.rb new file mode 100644 index 000000000..ffb12b6c6 --- /dev/null +++ b/spec/models/user_device_spec.rb @@ -0,0 +1,222 @@ +require 'rails_helper' + +RSpec.describe UserDevice, type: :model do + describe '.add' do + let(:existing_record) { UserDevice.add(user_agent, ip, agent.id, fingerprint, type) } + let(:ip) { '91.115.248.231' } + let(:agent) { create(:agent_user) } + + context 'with existing record of type: "session"' do + before { existing_record } # create existing record + + let(:user_agent) { 'Mozilla/5.0 (Macintosh; Intel Mac OS X 10_10_3) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/44.0.2403.107 Safari/537.36' } + let(:fingerprint) { 'fingerprint1234' } + let(:type) { 'session' } + + context 'when called with same parameters as existing record' do + it 'returns the original record' do + expect(UserDevice.add(user_agent, ip, agent.id, fingerprint, type)) + .to eq(existing_record) + end + end + + context 'when called with different IP from existing record' do + let(:other_ip) { '176.198.137.254' } + + it 'returns a new record' do + expect(UserDevice.add(user_agent, other_ip, agent.id, fingerprint, type)) + .to be_a(UserDevice) + .and not_eq(existing_record) + end + end + + context 'when called with invalid IP, not matching existing record' do + let(:other_ip) { 'foo' } + + it 'returns a new record' do + expect(UserDevice.add(user_agent, other_ip, agent.id, fingerprint, type)) + .to be_a(UserDevice) + .and not_eq(existing_record) + end + end + + context 'when called with different fingerprint from existing record' do + let(:other_fingerprint) { 'fingerprintABCD' } + + it 'returns a new record' do + expect(UserDevice.add(user_agent, ip, agent.id, other_fingerprint, type)) + .to be_a(UserDevice) + .and not_eq(existing_record) + end + end + + context 'with recognized user_agent (Mac/Chrome)' do + it 'assigns #user_agent attribute to given value' do + expect(existing_record.user_agent).to eq(user_agent) + end + + it 'derives #name attribute from given value' do + expect(existing_record.name).to eq('Mac, Chrome') + end + + it 'derives #browser attribute from given value' do + expect(existing_record.browser).to eq('Chrome') + end + end + + context 'with recognized user_agent (iOS/Safari)' do + let(:user_agent) { 'Mozilla/5.0 (iPhone; CPU iPhone OS 8_4 like Mac OS X) AppleWebKit/600.1.4 (KHTML, like Gecko) Version/8.0 Mobile/12H143 Safari/600.1.4' } + + it 'assigns #user_agent attribute to given value' do + expect(existing_record.user_agent).to eq(user_agent) + end + + it 'derives #name attribute from given value' do + expect(existing_record.name).to eq('Ios, Safari') + end + + it 'derives #browser attribute from given value' do + expect(existing_record.browser).to eq('Safari') + end + end + + context 'with partially recognized user_agent (Mac/CalendarAgent)' do + let(:user_agent) { 'Mac+OS+X/10.10.5 (14F27) CalendarAgent/316.1' } + + it 'assigns #user_agent and #browser attributes to given value' do + expect([existing_record.user_agent, existing_record.browser]) + .to all(eq(user_agent)) + end + + it 'derives #name attribute from given value' do + expect(existing_record.name).to eq("Mac, #{user_agent}") + end + end + + context 'with unrecognized user_agent' do + let(:user_agent) { 'foo' } + + it 'assigns #user_agent, #name, and #browser attributes to given value' do + expect([existing_record.user_agent, existing_record.name, existing_record.browser]) + .to all(eq(user_agent)) + end + end + end + + context 'with existing record of type: "basic_auth"' do + before { existing_record } # create existing record + + let(:user_agent) { 'curl/7.43.0' } + let(:fingerprint) { nil } + let(:type) { 'basic_auth' } + + context 'when called with same parameters as existing record' do + it 'returns the original record' do + expect(UserDevice.add(user_agent, ip, agent.id, fingerprint, type)) + .to eq(existing_record) + end + end + + context 'when called with different IP from existing record' do + let(:other_ip) { '176.198.137.254' } + + it 'returns a new record' do + expect(UserDevice.add(user_agent, other_ip, agent.id, fingerprint, type)) + .to be_a(UserDevice) + .and not_eq(existing_record) + end + end + + context 'when called with different type from existing record ("token_auth")' do + let(:other_type) { 'token_auth' } + + it 'returns the original record' do + expect(UserDevice.add(user_agent, ip, agent.id, fingerprint, other_type)) + .to eq(existing_record) + end + end + + context 'when called without existing record’s user agent' do + let(:other_user_agent) { '' } + + it 'returns a new record' do + expect(UserDevice.add(other_user_agent, ip, agent.id, fingerprint, type)) + .to be_a(UserDevice) + .and not_eq(existing_record) + end + end + + context 'when existing record’s user agent is blank, and given is nil' do + let(:user_agent) { '' } + let(:other_user_agent) { nil } + + it 'returns the original record' do + expect(UserDevice.add(other_user_agent, ip, agent.id, fingerprint, type)) + .to eq(existing_record) + end + end + + context 'when existing record and given args have nil user agent, but IPs don’t match' do + let(:user_agent) { nil } + let(:other_ip) { '176.198.137.254' } + + it 'returns a new record' do + expect(UserDevice.add(user_agent, other_ip, agent.id, fingerprint, type)) + .to be_a(UserDevice) + .and not_eq(existing_record) + end + end + end + + context 'with exceedingly long fingerprint (161+ chars)' do + let(:user_agent) { 'Mozilla/5.0 (Macintosh; Intel Mac OS X 10_10_3) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/44.0.2403.107 Safari/537.36' } + let(:fingerprint) { 'x' * 161 } + let(:type) { 'session' } + + it 'raises an error' do + expect { UserDevice.add(user_agent, ip, agent.id, fingerprint, type) } + .to raise_error(Exceptions::UnprocessableEntity) + end + end + end + + describe '.action' do + let(:user_device) { UserDevice.add(user_agent, ip, agent.id, fingerprint, type) } + let(:user_agent) { 'Mozilla/5.0 (Macintosh; Intel Mac OS X 10_10_3) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/44.0.2403.107 Safari/537.36' } + let(:ip) { '91.115.248.231' } + let(:agent) { create(:agent_user) } + let(:fingerprint) { 'fingerprint1234' } + let(:type) { 'session' } + + context 'when called with parameters matching given user_device' do + it 'returns the given user_device' do + expect(described_class.action(user_device.id, user_agent, ip, agent.id, type)) + .to eq(user_device) + end + end + + context 'when called with different IP from given user_device' do + let(:other_ip) { '176.198.137.254' } + + it 'returns a new user_device' do + expect(described_class.action(user_device.id, user_agent, other_ip, agent.id, type)) + .to be_a(UserDevice) + .and not_eq(user_device) + end + end + + context 'when called with invalid IP, not matching given user_device' do + let(:other_ip) { 'foo' } + + it 'returns the given user_device' do + expect(described_class.action(user_device.id, user_agent, other_ip, agent.id, type)) + .to eq(user_device) + end + + it 'sets user_device.ip to the given (invalid) IP' do + expect { described_class.action(user_device.id, user_agent, other_ip, agent.id, type) } + .to change { user_device.reload.ip }.to(other_ip) + end + end + end +end diff --git a/spec/support/negated_matchers.rb b/spec/support/negated_matchers.rb index 539f78048..03e45fd3b 100644 --- a/spec/support/negated_matchers.rb +++ b/spec/support/negated_matchers.rb @@ -1,2 +1,3 @@ RSpec::Matchers.define_negated_matcher :not_change, :change RSpec::Matchers.define_negated_matcher :not_include, :include +RSpec::Matchers.define_negated_matcher :not_eq, :eq diff --git a/test/unit/user_device_test.rb b/test/unit/user_device_test.rb deleted file mode 100644 index 1511df694..000000000 --- a/test/unit/user_device_test.rb +++ /dev/null @@ -1,332 +0,0 @@ -require 'test_helper' - -class UserDeviceTest < ActiveSupport::TestCase - setup do - - UserInfo.current_user_id = 1 - - groups = Group.all - roles = Role.where(name: 'Agent') - @agent = User.create_or_update( - login: 'user-device-agent@example.com', - firstname: 'UserDevice', - lastname: 'Agent', - email: 'user-device-agent@example.com', - password: 'agentpw', - active: true, - roles: roles, - groups: groups, - ) - - roles = Role.where(name: 'Customer') - @customer = User.create_or_update( - login: 'user-device-customer@example.com', - firstname: 'UserDevice', - lastname: 'Customer', - email: 'user-device-customer@example.com', - password: 'customerpw', - active: true, - roles: roles, - ) - end - - test 'aaa - session test' do - - # signin with fingerprint A from country A via session -> new device #1 - user_device1 = UserDevice.add( - 'Mozilla/5.0 (Macintosh; Intel Mac OS X 10_10_3) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/44.0.2403.107 Safari/537.36', - '91.115.248.231', - @agent.id, - 'fingerprint1234', - 'session', - ) - - # signin with fingerprint A from country B via session -> new device #2 - user_device2 = UserDevice.add( - 'Mozilla/5.0 (Macintosh; Intel Mac OS X 10_10_3) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/44.0.2403.107 Safari/537.36', - '176.198.137.254', - @agent.id, - 'fingerprint1234', - 'session', - ) - assert_not_equal(user_device1.id, user_device2.id) - - # signin with fingerprint B from country A via session -> new device #3 - user_device3 = UserDevice.add( - 'Mozilla/5.0 (Macintosh; Intel Mac OS X 10_10_3) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/44.0.2403.107 Safari/537.36', - '91.115.248.231', - @agent.id, - 'fingerprintABC', - 'session', - ) - assert_not_equal(user_device2.id, user_device3.id) - - # signin with fingerprint A from country A via session -> new device #1 - user_device4 = UserDevice.add( - 'Mozilla/5.0 (Macintosh; Intel Mac OS X 10_10_3) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/44.0.2403.107 Safari/537.36', - '91.115.248.231', - @agent.id, - 'fingerprint1234', - 'session', - ) - assert_equal(user_device1.id, user_device4.id) - - # signin with fingerprint A from country B via session -> new device #2 - user_device5 = UserDevice.add( - 'Mozilla/5.0 (Macintosh; Intel Mac OS X 10_10_3) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/44.0.2403.107 Safari/537.36', - '176.198.137.254', - @agent.id, - 'fingerprint1234', - 'session', - ) - assert_equal(user_device2.id, user_device5.id) - - # signin with fingerprint B from country A via session -> new device #3 - user_device6 = UserDevice.add( - 'Mozilla/5.0 (Macintosh; Intel Mac OS X 10_10_3) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/44.0.2403.107 Safari/537.36', - '91.115.248.231', - @agent.id, - 'fingerprintABC', - 'session', - ) - assert_equal(user_device3.id, user_device6.id) - - end - - test 'bbb - session test - user agent (unknown)' do - - # known user agent - user_device1 = UserDevice.add( - 'Mozilla/5.0 (Macintosh; Intel Mac OS X 10_10_3) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/44.0.2403.107 Safari/537.36', - '91.115.248.231', - @agent.id, - nil, - 'session', - ) - assert_equal('Mozilla/5.0 (Macintosh; Intel Mac OS X 10_10_3) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/44.0.2403.107 Safari/537.36', user_device1.user_agent) - assert_equal('Mac, Chrome', user_device1.name) - - # unknown user agent - user_device2 = UserDevice.add( - 'ABC 123', - '91.115.248.231', - @agent.id, - nil, - 'session', - ) - assert_equal('ABC 123', user_device2.user_agent) - assert_equal('ABC 123', user_device2.browser) - assert_equal('ABC 123', user_device2.name) - - # partently known - user_device3 = UserDevice.add( - 'Mozilla/5.0 (iPhone; CPU iPhone OS 8_4 like Mac OS X) AppleWebKit/600.1.4 (KHTML, like Gecko) Version/8.0 Mobile/12H143 Safari/600.1.4', - '91.115.248.231', - @agent.id, - nil, - 'session', - ) - assert_equal('Mozilla/5.0 (iPhone; CPU iPhone OS 8_4 like Mac OS X) AppleWebKit/600.1.4 (KHTML, like Gecko) Version/8.0 Mobile/12H143 Safari/600.1.4', user_device3.user_agent) - assert_equal('Safari', user_device3.browser) - assert_equal('Ios, Safari', user_device3.name) - - user_device4 = UserDevice.add( - 'Mac+OS+X/10.10.5 (14F27) CalendarAgent/316.1', - '91.115.248.231', - @agent.id, - nil, - 'session', - ) - assert_equal('Mac+OS+X/10.10.5 (14F27) CalendarAgent/316.1', user_device4.user_agent) - assert_equal('Mac+OS+X/10.10.5 (14F27) CalendarAgent/316.1', user_device4.browser) - assert_equal('Mac, Mac+OS+X/10.10.5 (14F27) CalendarAgent/316.1', user_device4.name) - - end - - test 'ccc - api test' do - - # signin with ua from country A via basic auth -> new device #1 - user_device1 = UserDevice.add( - 'curl/7.43.0', - '91.115.248.231', - @agent.id, - nil, - 'basic_auth', - ) - - # signin with ua from country B via basic auth -> new device #2 - user_device2 = UserDevice.add( - 'curl/7.43.0', - '176.198.137.254', - @agent.id, - nil, - 'basic_auth', - ) - assert_not_equal(user_device1.id, user_device2.id) - - # signin with ua from country A via basic auth -> new device #1 - user_device3 = UserDevice.add( - 'curl/7.43.0', - '91.115.248.231', - @agent.id, - nil, - 'basic_auth', - ) - assert_equal(user_device1.id, user_device3.id) - - # signin with ua from country B via basic auth -> new device #2 - user_device4 = UserDevice.add( - 'curl/7.43.0', - '176.198.137.254', - @agent.id, - nil, - 'basic_auth', - ) - assert_equal(user_device2.id, user_device4.id) - - # signin with ua from country A via token auth -> new device #1 - user_device5 = UserDevice.add( - 'curl/7.43.0', - '91.115.248.231', - @agent.id, - nil, - 'token_auth', - ) - assert_equal(user_device1.id, user_device5.id) - - # signin with ua from country B via token auth -> new device #2 - user_device6 = UserDevice.add( - 'curl/7.43.0', - '176.198.137.254', - @agent.id, - nil, - 'token_auth', - ) - assert_equal(user_device2.id, user_device6.id) - - # signin without ua from country A via basic auth -> new device #3 - user_device7 = UserDevice.add( - '', - '91.115.248.231', - @agent.id, - nil, - 'basic_auth', - ) - assert_not_equal(user_device6.id, user_device7.id) - - user_device8 = UserDevice.add( - '', - '91.115.248.231', - @agent.id, - nil, - 'basic_auth', - ) - assert_equal(user_device7.id, user_device8.id) - - user_device9 = UserDevice.add( - nil, - '91.115.248.231', - @agent.id, - nil, - 'basic_auth', - ) - assert_equal(user_device8.id, user_device9.id) - - user_device10 = UserDevice.add( - nil, - '176.198.137.254', - @agent.id, - nil, - 'basic_auth', - ) - assert_not_equal(user_device9.id, user_device10.id) - end - - test 'ddd - api test' do - - # signin with fingerprint A from country A via session -> new device #1 - user_device1 = UserDevice.add( - 'Mozilla/5.0 (Macintosh; Intel Mac OS X 10_10_3) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/44.0.2403.107 Safari/537.36', - '91.115.248.231', - @agent.id, - 'fingerprint1234', - 'session', - ) - - # action with same fingerprint -> same device - user_device1_1 = UserDevice.action( - user_device1.id, - 'Mozilla/5.0 (Macintosh; Intel Mac OS X 10_10_3) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/44.0.2403.107 Safari/537.36', - '91.115.248.231', - @agent.id, - 'session', - ) - assert_equal(user_device1.id, user_device1_1.id) - - # signin with same fingerprint -> same device - user_device1_2 = UserDevice.add( - 'Mozilla/5.0 (Macintosh; Intel Mac OS X 10_10_3) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/44.0.2403.107 Safari/537.36', - '91.115.248.231', - @agent.id, - 'fingerprint1234', - 'session', - ) - assert_equal(user_device1.id, user_device1_2.id) - - # action with different fingerprint -> new device - user_device1_3 = UserDevice.add( - 'Mozilla/5.0 (Macintosh; Intel Mac OS X 10_10_3) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/44.0.2403.107 Safari/537.36', - '91.115.248.231', - @agent.id, - 'fingerprintABC', - 'session', - ) - assert_not_equal(user_device1.id, user_device1_3.id) - - # signin with without accessable location -> new device - user_device1_4 = UserDevice.add( - 'Mozilla/5.0 (Macintosh; Intel Mac OS X 10_10_3) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/44.0.2403.107 Safari/537.36', - 'not_existing_ip', - @agent.id, - 'fingerprintABC', - 'session', - ) - assert_not_equal(user_device1.id, user_device1_4.id) - - # action with fingerprint A from country B via session -> new device #2 - user_device2 = UserDevice.action( - user_device1.id, - 'Mozilla/5.0 (Macintosh; Intel Mac OS X 10_10_3) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/44.0.2403.107 Safari/537.36', - '176.198.137.254', - @agent.id, - 'session', - ) - assert_not_equal(user_device1.id, user_device2.id) - - # action with fingerprint A without accessable location -> use current device #2 - user_device3 = UserDevice.action( - user_device2.id, - 'Mozilla/5.0 (Macintosh; Intel Mac OS X 10_10_3) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/44.0.2403.107 Safari/537.36', - 'not_existing_ip', - @agent.id, - 'session', - ) - assert_equal(user_device2.id, user_device3.id) - - end - - test 'invalid fingerprint size' do - - assert_raises(Exceptions::UnprocessableEntity) do - UserDevice.add( - 'Mozilla/5.0 (Macintosh; Intel Mac OS X 10_10_3) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/44.0.2403.107 Safari/537.36', - '91.115.248.231', - @agent.id, - 'fingerprint1234fingerprint1234fingerprint1234fingerprint1234fingerprint1234fingerprint1234fingerprint1234fingerprint1234fingerprint1234fingerprint1234fingerprint1234', - 'session', - ) - end - - end - -end