From 03fab14ef34c37745760f1a24df12348cc2b86a5 Mon Sep 17 00:00:00 2001 From: Seth Call Date: Sun, 21 Feb 2021 15:07:31 -0600 Subject: [PATCH] Add more test cases and logic changes --- ruby/lib/jam_ruby/models/connection.rb | 4 +- .../models/music_session_user_history.rb | 36 ++-- ruby/lib/jam_ruby/models/user.rb | 4 + ruby/lib/jam_ruby/recurly_client.rb | 3 +- .../music_sessions_user_history_spec.rb | 181 +++++++++++++++++- 5 files changed, 204 insertions(+), 24 deletions(-) diff --git a/ruby/lib/jam_ruby/models/connection.rb b/ruby/lib/jam_ruby/models/connection.rb index 73b2ad774..a6a96b315 100644 --- a/ruby/lib/jam_ruby/models/connection.rb +++ b/ruby/lib/jam_ruby/models/connection.rb @@ -168,13 +168,13 @@ module JamRuby num_participants = music_session.users.count - puts "NUM PARTICIPANTS BEFORE JOIN #{num_participants}" subscription_rules = self.user.subscription_rules(dynamic_definitions = false) max_players = subscription_rules[:max_players] if !max_players.nil? if num_participants >= max_players - errors.add(:music_session, ValidationMessages::PLAN_PROHIBIT_MAX_PLAYERS) + # temporarily disable enforcement of this per David's request due to high support volume + #errors.add(:music_session, ValidationMessages::PLAN_PROHIBIT_MAX_PLAYERS) end end diff --git a/ruby/lib/jam_ruby/models/music_session_user_history.rb b/ruby/lib/jam_ruby/models/music_session_user_history.rb index 0972f49e7..66d782f6f 100644 --- a/ruby/lib/jam_ruby/models/music_session_user_history.rb +++ b/ruby/lib/jam_ruby/models/music_session_user_history.rb @@ -61,17 +61,27 @@ module JamRuby # end #take duration that this user session was with other - # + # use this as a base: https://wiki.postgresql.org/wiki/Range_aggregation + # But the 'intervals' table from that example is instead our own 'compute intersections' from this msuh and all others in the same session not of the same user ID def duration_minutes + created_at_db = self.created_at.utc.strftime '%Y-%m-%d %H:%M:%S' + session_removed_at_db = self.session_removed_at.utc.strftime '%Y-%m-%d %H:%M:%S' query = <<-SQL - select sum(upper(diff) - lower(diff)) as duration - FROM ( - SELECT tsrange(created_at, session_removed_at, '[]') * tsrange('#{self.created_at.strftime '%Y-%m-%d %H:%M:%S'}', '#{self.session_removed_at.strftime '%Y-%m-%d %H:%M:%S'}', '[]') AS diff - FROM music_sessions_user_history - WHERE music_session_id = '#{self.music_session_id}' - AND id <> '#{self.id}' - - ) AS derivedTable + SELECT sum(e - s) as duration + FROM + (SELECT min(s) as s, max(e) as e + FROM (SELECT s, e, + MAX(new_start) OVER (ORDER BY s,e) AS left_edge + FROM + (SELECT s, e, CASE WHEN s < max(le) OVER (ORDER BY s,e) THEN null ELSE s END AS new_start + FROM (SELECT s, e, lag(e) OVER (ORDER BY s,e) AS le FROM + (SELECT UPPER(diff) as e, LOWER(diff) as s FROM (SELECT tsrange(created_at, COALESCE(session_removed_at, '#{session_removed_at_db}'), '[]') * tsrange('#{created_at_db}', '#{session_removed_at_db}', '[]') AS diff + FROM music_sessions_user_history + WHERE music_session_id = '#{self.music_session_id}' + AND created_at <= '#{session_removed_at_db}' + AND (user_id <> '#{self.user_id}')) AS intervals) as tah + ) s1) s2) s3 + GROUP BY left_edge) as cleaned SQL result = ActiveRecord::Base.connection.exec_query(query) duration = result.cast_values[0] @@ -109,9 +119,11 @@ SQL if self.session_removed_at.nil? self.session_removed_at = Time.now end - self.max_concurrent_connections = determine_max_concurrent - self.update_attributes(:session_removed_at => self.session_removed_at, :max_concurrent_connections => self.max_concurrent_connections) - self.update_remaining_play_time + if self.max_concurrent_connections.nil? + self.max_concurrent_connections = determine_max_concurrent + self.update_attributes(:session_removed_at => self.session_removed_at, :max_concurrent_connections => self.max_concurrent_connections) + self.update_remaining_play_time + end end # update the users monthly play time diff --git a/ruby/lib/jam_ruby/models/user.rb b/ruby/lib/jam_ruby/models/user.rb index 5cf5b4f4b..feb65edb8 100644 --- a/ruby/lib/jam_ruby/models/user.rb +++ b/ruby/lib/jam_ruby/models/user.rb @@ -2872,6 +2872,10 @@ module JamRuby SubscriptionDefinitions.rules(self.subscription_plan_code)[:has_support] end + def reset_playtime + self.used_month_play_time = 0 + end + def subscription_rules(dynamic_definitions = true) rules = SubscriptionDefinitions.rules(self.subscription_plan_code) if dynamic_definitions diff --git a/ruby/lib/jam_ruby/recurly_client.rb b/ruby/lib/jam_ruby/recurly_client.rb index 507c127e9..dfe38a723 100644 --- a/ruby/lib/jam_ruby/recurly_client.rb +++ b/ruby/lib/jam_ruby/recurly_client.rb @@ -360,7 +360,7 @@ module JamRuby end end - + current_user.reset_playtime current_user.save(validate: false) rescue => e puts "Could not create subscription for user #{current_user.email}. #{e}" @@ -604,6 +604,7 @@ module JamRuby if user.subscription_plan_code != user.desired_plan_code puts "they are back! get them back into their desired plan #{user.email}" if !SubscriptionDefinitions.is_downgrade(user.desired_plan_code, user.subscription_plan_code) + user.reset_playtime user.subscription_plan_code = user.desired_plan_code user.subscription_plan_code_set_at = DateTime.now user.subscription_sync_code = 'good_standing_repaired' diff --git a/ruby/spec/jam_ruby/models/music_sessions_user_history_spec.rb b/ruby/spec/jam_ruby/models/music_sessions_user_history_spec.rb index be2316e1a..83236683e 100644 --- a/ruby/spec/jam_ruby/models/music_sessions_user_history_spec.rb +++ b/ruby/spec/jam_ruby/models/music_sessions_user_history_spec.rb @@ -3,6 +3,7 @@ require 'spec_helper' describe MusicSessionUserHistory do let(:some_user) { FactoryGirl.create(:user) } + let(:some_other_user) { FactoryGirl.create(:user) } let(:music_session) { FactoryGirl.create(:active_music_session_no_user_history) } let(:user_history1) { FactoryGirl.create(:music_session_user_history, :history => music_session.music_session, :user => music_session.creator) } let(:user_history2) { FactoryGirl.create(:music_session_user_history, :history => music_session.music_session, :user => some_user) } @@ -104,8 +105,12 @@ describe MusicSessionUserHistory do user_history2.created_at = user_history1.created_at - 1 user_history2.session_removed_at = user_history1.created_at + 2 + #user_history1.save.should be_true user_history2.save.should be_true - + + expect(user_history1.session_removed_at).to be > user_history1.created_at + expect(user_history2.session_removed_at).to be > user_history2.created_at + user_history1.reload user_history2.reload user_history1.end_history @@ -123,6 +128,7 @@ describe MusicSessionUserHistory do user_history1.reload user_history2.reload + user_history1.end_history user_history1.max_concurrent_connections.should == 2 @@ -205,38 +211,32 @@ describe MusicSessionUserHistory do describe "duration_minutes" do it "returns zero when history2 ends before history1 starts" do - user_history1.session_removed_at = user_history1.created_at + 5 user_history2.created_at = user_history1.created_at - 2 user_history2.session_removed_at = user_history1.created_at - 1 user_history2.save.should be_true - user_history1.reload user_history2.reload user_history1.end_history expect(user_history1.duration_minutes).to eq 0 - end - it "returns zero when history2 starts after history1 ends" do user_history1.session_removed_at = user_history1.created_at + 5 user_history2.created_at = user_history1.session_removed_at + 1 user_history2.session_removed_at = user_history1.session_removed_at + 2 - + user_history2.save.should be_true - user_history1.reload user_history2.reload user_history1.end_history #user_history1.max_concurrent_connections.should == 1 expect(user_history1.duration_minutes).to eq 0 - end @@ -256,6 +256,29 @@ describe MusicSessionUserHistory do expect(user_history1.duration_minutes).to eq 2 end + it "returns overlapped time when history2 is within bounds of history1 -- idempotent" do + #pending + user_history1.session_removed_at = user_history1.created_at + 3*60 + user_history2.created_at = user_history1.created_at + 1*60 + user_history2.session_removed_at = user_history1.created_at + 3*60 + + user_history1.save.should be_true + user_history2.save.should be_true + + user_history1.reload + user_history2.reload + user_history1.end_history + expect(user_history1.duration_minutes).to eq 2 + music_session.creator.reload + expect(music_session.creator.used_month_play_time).to eq (2 * 60) + + # call it a second tiem + user_history1.end_history + expect(user_history1.duration_minutes).to eq 2 + music_session.creator.reload + expect(music_session.creator.used_month_play_time).to eq (2 * 60) + end + it "returns overlapped time when history2 begings before history1 start and terminates before history1 end" do user_history1.session_removed_at = user_history1.created_at + 3*60 user_history2.created_at = user_history1.created_at - 1*60 @@ -283,8 +306,148 @@ describe MusicSessionUserHistory do user_history1.end_history expect(user_history1.duration_minutes).to eq 2 - end + + it "same user in same session does not rack up time" do + + same_user_history = FactoryGirl.create(:music_session_user_history, :history => music_session.music_session, :user => music_session.creator) + + user_history1.session_removed_at = user_history1.created_at + 3*60 + same_user_history.created_at = user_history1.created_at + 1*60 + same_user_history.session_removed_at = user_history1.created_at + 4*60 + + expect(user_history1.save).to eq true + expect(same_user_history.save).to eq true + + user_history1.end_history + + expect(user_history1.duration_minutes).to eq 0 + end + + it "3rd user has no bearing on accumulated time if same overlapping as 2nd user" do + user_history1.session_removed_at = user_history1.created_at + 3*60 + user_history2.created_at = user_history1.created_at + 1*60 + user_history2.session_removed_at = user_history1.created_at + 4*60 + user_history3 = FactoryGirl.create(:music_session_user_history, :history => music_session.music_session, :user => some_other_user) + user_history3.created_at = user_history1.created_at + 1*60 + user_history3.session_removed_at = user_history1.created_at + 4*60 + + expect(user_history1.save).to eq true + expect(user_history2.save).to eq true + expect(user_history3.save).to eq true + + user_history1.end_history + + expect(user_history1.duration_minutes).to eq 2 + end + + it "3rd user has some bearing on accumulated time if different overlapping as 2nd user" do + user_history1.session_removed_at = user_history1.created_at + 7*60 + user_history2.created_at = user_history1.created_at + 1*60 + user_history2.session_removed_at = user_history1.created_at + 3*60 + user_history3 = FactoryGirl.create(:music_session_user_history, :history => music_session.music_session, :user => some_other_user) + user_history3.created_at = user_history1.created_at + 2*60 + user_history3.session_removed_at = user_history1.created_at + 4*60 + + expect(user_history1.save).to eq true + expect(user_history2.save).to eq true + expect(user_history3.save).to eq true + + user_history1.end_history + + expect(user_history1.duration_minutes).to eq 3 + end + + it "two users where 1st guy leaves last, and no save of that record" do + user_history1.session_removed_at = user_history1.created_at + 7*60 + user_history2.created_at = user_history1.created_at - 1*60 + user_history2.session_removed_at = user_history1.created_at + 3*60 + + expect(user_history2.save).to eq true + + user_history1.end_history + + expect(user_history1.duration_minutes).to eq 3 + end + + it "two users where users all leaves, but then come back to same session 2x" do + user_history1.session_removed_at = user_history1.created_at + 7*60 + user_history2.created_at = user_history1.created_at - 1*60 + user_history2.session_removed_at = user_history1.created_at + 3*60 + + expect(user_history2.save).to eq true + + user_history1.end_history + + # validate duration minutes works + expect(user_history1.duration_minutes).to eq 3 + expect(music_session.creator.used_month_play_time).to be_nil + music_session.creator.reload + # and validate that the users rolling monthly play time is tracked correctly + expect(music_session.creator.used_month_play_time).to eq 3 * 60 # this field tracks per second + expect(music_session.creator.used_current_month).to eq (User.current_month) + + + # COME BACK INTO SAME SESSION LATER + + user_history1_returns = FactoryGirl.create(:music_session_user_history, :history => music_session.music_session, :user => music_session.creator) + user_history2_returns = FactoryGirl.create(:music_session_user_history, :history => music_session.music_session, :user => some_user) + + user_history1_returns.created_at = user_history1.created_at + 8*60 + user_history1_returns.session_removed_at = user_history1.created_at + 16*60 + user_history2_returns.created_at = user_history1.created_at + 7*60 + user_history2_returns.session_removed_at = user_history1.created_at + 12*60 + + expect(user_history1_returns.save).to eq true + expect(user_history2_returns.save).to eq true + + user_history1_returns.end_history + + expect(user_history1_returns.duration_minutes).to eq 4 + expect(music_session.creator.used_month_play_time).to eq 3 * 60 + music_session.creator.reload + # validate that the users rolling monthly play time is still tracked correctly + expect(music_session.creator.used_month_play_time).to eq (3 + 4) * 60 # 3 minutes + 4 minutes should be 7 + + + # AND COME BACK ONCE MORE + user_history1_returns2 = FactoryGirl.create(:music_session_user_history, :history => music_session.music_session, :user => music_session.creator) + user_history2_returns2 = FactoryGirl.create(:music_session_user_history, :history => music_session.music_session, :user => some_user) + + user_history1_returns2.created_at = user_history1.created_at + 20*60 + user_history1_returns2.session_removed_at = user_history1.created_at + 25*60 + user_history2_returns2.created_at = user_history1.created_at + 21*60 + user_history2_returns2.session_removed_at = user_history1.created_at + 22*60 + + expect(user_history1_returns2.save).to eq true + expect(user_history2_returns2.save).to eq true + + user_history1_returns2.end_history + + expect(user_history1_returns2.duration_minutes).to eq 1 + expect(music_session.creator.used_month_play_time).to eq (3 + 4) * 60 + music_session.creator.reload + # validate that the users rolling monthly play time is still tracked correctly + expect(music_session.creator.used_month_play_time).to eq (3 + 4 + 1) * 60 + end + + it "a null session_removed of other substituted with the msuh's session_removed" do + user_history1.session_removed_at = user_history1.created_at + 7*60 + user_history2.created_at = user_history1.created_at + 1*60 + user_history2.session_removed_at = nil + user_history3 = FactoryGirl.create(:music_session_user_history, :history => music_session.music_session, :user => some_other_user) + user_history3.created_at = user_history1.created_at + 2*60 + user_history3.session_removed_at = nil + + expect(user_history1.save).to eq true + expect(user_history2.save).to eq true + expect(user_history3.save).to eq true + + user_history1.end_history + + expect(user_history1.duration_minutes).to eq 6 + end + end end