From 50bd60dd51fb483330d1ca52f0056e9e2b783166 Mon Sep 17 00:00:00 2001 From: James Allen Date: Mon, 21 May 2018 15:06:01 +0100 Subject: [PATCH] Split FeaturesUpdater out of SubscriptionUpdater --- .../Subscription/FeaturesUpdater.coffee | 83 ++++++++ .../SubscriptionController.coffee | 4 +- .../Subscription/SubscriptionUpdater.coffee | 88 +-------- .../acceptance/config/settings.test.coffee | 6 - .../Subscription/FeaturesUpdaterTests.coffee | 173 ++++++++++++++++ .../SubscriptionControllerTests.coffee | 2 +- .../SubscriptionUpdaterTests.coffee | 184 ++---------------- 7 files changed, 284 insertions(+), 256 deletions(-) create mode 100644 services/web/app/coffee/Features/Subscription/FeaturesUpdater.coffee create mode 100644 services/web/test/unit/coffee/Subscription/FeaturesUpdaterTests.coffee diff --git a/services/web/app/coffee/Features/Subscription/FeaturesUpdater.coffee b/services/web/app/coffee/Features/Subscription/FeaturesUpdater.coffee new file mode 100644 index 0000000000..5c176c611f --- /dev/null +++ b/services/web/app/coffee/Features/Subscription/FeaturesUpdater.coffee @@ -0,0 +1,83 @@ +async = require("async") +PlansLocator = require("./PlansLocator") +_ = require("underscore") +SubscriptionLocator = require("./SubscriptionLocator") +UserFeaturesUpdater = require("./UserFeaturesUpdater") +Settings = require("settings-sharelatex") +logger = require("logger-sharelatex") +ReferalFeatures = require("../Referal/ReferalFeatures") +V1SubscriptionManager = require("./V1SubscriptionManager") + +oneMonthInSeconds = 60 * 60 * 24 * 30 + +module.exports = FeaturesUpdater = + refreshFeatures: (user_id, callback)-> + jobs = + individualFeatures: (cb) -> FeaturesUpdater._getIndividualFeatures user_id, cb + groupFeatureSets: (cb) -> FeaturesUpdater._getGroupFeatureSets user_id, cb + v1Features: (cb) -> FeaturesUpdater._getV1Features user_id, cb + bonusFeatures: (cb) -> ReferalFeatures.getBonusFeatures user_id, cb + async.series jobs, (err, results)-> + if err? + logger.err err:err, user_id:user_id, + "error getting subscription or group for refreshFeatures" + return callback(err) + + {individualFeatures, groupFeatureSets, v1Features, bonusFeatures} = results + logger.log {user_id, individualFeatures, groupFeatureSets, v1Features, bonusFeatures}, 'merging user features' + featureSets = groupFeatureSets.concat [individualFeatures, v1Features, bonusFeatures] + features = _.reduce(featureSets, FeaturesUpdater._mergeFeatures, Settings.defaultFeatures) + + logger.log {user_id, features}, 'updating user features' + UserFeaturesUpdater.updateFeatures user_id, features, callback + + _getIndividualFeatures: (user_id, callback = (error, features = {}) ->) -> + SubscriptionLocator.getUsersSubscription user_id, (err, sub)-> + callback err, FeaturesUpdater._subscriptionToFeatures(sub) + + _getGroupFeatureSets: (user_id, callback = (error, featureSets = []) ->) -> + SubscriptionLocator.getGroupSubscriptionsMemberOf user_id, (err, subs) -> + callback err, (subs or []).map FeaturesUpdater._subscriptionToFeatures + + _getV1Features: (user_id, callback = (error, features = {}) ->) -> + V1SubscriptionManager.getPlanCodeFromV1 user_id, (err, planCode) -> + callback err, FeaturesUpdater._planCodeToFeatures(planCode) + + _mergeFeatures: (featuresA, featuresB) -> + features = Object.assign({}, featuresA) + for key, value of featuresB + # Special merging logic for non-boolean features + if key == 'compileGroup' + if features['compileGroup'] == 'priority' or featuresB['compileGroup'] == 'priority' + features['compileGroup'] = 'priority' + else + features['compileGroup'] = 'standard' + else if key == 'collaborators' + if features['collaborators'] == -1 or featuresB['collaborators'] == -1 + features['collaborators'] = -1 + else + features['collaborators'] = Math.max( + features['collaborators'] or 0, + featuresB['collaborators'] or 0 + ) + else if key == 'compileTimeout' + features['compileTimeout'] = Math.max( + features['compileTimeout'] or 0, + featuresB['compileTimeout'] or 0 + ) + else + # Boolean keys, true is better + features[key] = features[key] or featuresB[key] + return features + + _subscriptionToFeatures: (subscription) -> + FeaturesUpdater._planCodeToFeatures(subscription?.planCode) + + _planCodeToFeatures: (planCode) -> + if !planCode? + return {} + plan = PlansLocator.findLocalPlanInSettings planCode + if !plan? + return {} + else + return plan.features \ No newline at end of file diff --git a/services/web/app/coffee/Features/Subscription/SubscriptionController.coffee b/services/web/app/coffee/Features/Subscription/SubscriptionController.coffee index f127f7ed35..32d2abf594 100644 --- a/services/web/app/coffee/Features/Subscription/SubscriptionController.coffee +++ b/services/web/app/coffee/Features/Subscription/SubscriptionController.coffee @@ -9,7 +9,7 @@ logger = require('logger-sharelatex') GeoIpLookup = require("../../infrastructure/GeoIpLookup") SubscriptionDomainHandler = require("./SubscriptionDomainHandler") UserGetter = require "../User/UserGetter" -SubscriptionUpdater = require './SubscriptionUpdater' +FeaturesUpdater = require './FeaturesUpdater' module.exports = SubscriptionController = @@ -241,6 +241,6 @@ module.exports = SubscriptionController = refreshUserFeatures: (req, res, next) -> {user_id} = req.params - SubscriptionUpdater.refreshFeatures user_id, (error) -> + FeaturesUpdater.refreshFeatures user_id, (error) -> return next(error) if error? res.sendStatus 200 \ No newline at end of file diff --git a/services/web/app/coffee/Features/Subscription/SubscriptionUpdater.coffee b/services/web/app/coffee/Features/Subscription/SubscriptionUpdater.coffee index 8e583bd07b..cb5c39d122 100644 --- a/services/web/app/coffee/Features/Subscription/SubscriptionUpdater.coffee +++ b/services/web/app/coffee/Features/Subscription/SubscriptionUpdater.coffee @@ -2,27 +2,26 @@ async = require("async") _ = require("underscore") Subscription = require('../../models/Subscription').Subscription SubscriptionLocator = require("./SubscriptionLocator") -UserFeaturesUpdater = require("./UserFeaturesUpdater") PlansLocator = require("./PlansLocator") Settings = require("settings-sharelatex") logger = require("logger-sharelatex") -ObjectId = require('mongoose').Types.ObjectId -ReferalFeatures = require("../Referal/ReferalFeatures") -V1SubscriptionManager = require("./V1SubscriptionManager") +ObjectId = require('mongoose').Types.ObjectId +FeaturesUpdater = require('./FeaturesUpdater') oneMonthInSeconds = 60 * 60 * 24 * 30 module.exports = SubscriptionUpdater = - syncSubscription: (recurlySubscription, adminUser_id, callback) -> logger.log adminUser_id:adminUser_id, recurlySubscription:recurlySubscription, "syncSubscription, creating new if subscription does not exist" SubscriptionLocator.getUsersSubscription adminUser_id, (err, subscription)-> + return callback(err) if err? if subscription? logger.log adminUser_id:adminUser_id, recurlySubscription:recurlySubscription, "subscription does exist" SubscriptionUpdater._updateSubscriptionFromRecurly recurlySubscription, subscription, callback else logger.log adminUser_id:adminUser_id, recurlySubscription:recurlySubscription, "subscription does not exist, creating a new one" SubscriptionUpdater._createNewSubscription adminUser_id, (err, subscription)-> + return callback(err) if err? SubscriptionUpdater._updateSubscriptionFromRecurly recurlySubscription, subscription, callback addUserToGroup: (adminUser_id, user_id, callback)-> @@ -35,7 +34,7 @@ module.exports = SubscriptionUpdater = if err? logger.err err:err, searchOps:searchOps, insertOperation:insertOperation, "error findy and modify add user to group" return callback(err) - UserFeaturesUpdater.updateFeatures user_id, subscription.planCode, callback + FeaturesUpdater.refreshFeatures user_id, callback addEmailInviteToGroup: (adminUser_id, email, callback) -> logger.log {adminUser_id, email}, "adding email into mongo subscription" @@ -54,7 +53,7 @@ module.exports = SubscriptionUpdater = if err? logger.err err:err, searchOps:searchOps, removeOperation:removeOperation, "error removing user from group" return callback(err) - SubscriptionUpdater.refreshFeatures user_id, callback + FeaturesUpdater.refreshFeatures user_id, callback removeEmailInviteFromGroup: (adminUser_id, email, callback)-> Subscription.update { @@ -70,7 +69,7 @@ module.exports = SubscriptionUpdater = logger.log {subscription_id, affected_user_ids}, "deleting subscription and downgrading users" Subscription.remove {_id: ObjectId(subscription_id)}, (err) -> return callback(err) if err? - async.mapSeries affected_user_ids, SubscriptionUpdater.refreshFeatures, callback + async.mapSeries affected_user_ids, FeaturesUpdater.refreshFeatures, callback _createNewSubscription: (adminUser_id, callback)-> logger.log adminUser_id:adminUser_id, "creating new subscription" @@ -98,76 +97,5 @@ module.exports = SubscriptionUpdater = allIds = _.union subscription.member_ids, [subscription.admin_id] jobs = allIds.map (user_id)-> return (cb)-> - SubscriptionUpdater.refreshFeatures user_id, cb + FeaturesUpdater.refreshFeatures user_id, cb async.series jobs, callback - - refreshFeatures: (user_id, callback)-> - jobs = - individualFeatures: (cb) -> SubscriptionUpdater._getIndividualFeatures user_id, cb - groupFeatureSets: (cb) -> SubscriptionUpdater._getGroupFeatureSets user_id, cb - v1Features: (cb) -> SubscriptionUpdater._getV1Features user_id, cb - bonusFeatures: (cb) -> ReferalFeatures.getBonusFeatures user_id, cb - async.series jobs, (err, results)-> - if err? - logger.err err:err, user_id:user_id, - "error getting subscription or group for refreshFeatures" - return callback(err) - - {individualFeatures, groupFeatureSets, v1Features, bonusFeatures} = results - logger.log {user_id, individualFeatures, groupFeatureSets, v1Features, bonusFeatures}, 'merging user features' - featureSets = groupFeatureSets.concat [individualFeatures, v1Features, bonusFeatures] - features = _.reduce(featureSets, SubscriptionUpdater._mergeFeatures, Settings.defaultFeatures) - - logger.log {user_id, features}, 'updating user features' - UserFeaturesUpdater.updateFeatures user_id, features, callback - - _getIndividualFeatures: (user_id, callback = (error, features = {}) ->) -> - SubscriptionLocator.getUsersSubscription user_id, (err, sub)-> - callback err, SubscriptionUpdater._subscriptionToFeatures(sub) - - _getGroupFeatureSets: (user_id, callback = (error, featureSets = []) ->) -> - SubscriptionLocator.getGroupSubscriptionsMemberOf user_id, (err, subs) -> - callback err, (subs or []).map SubscriptionUpdater._subscriptionToFeatures - - _getV1Features: (user_id, callback = (error, features = {}) ->) -> - V1SubscriptionManager.getPlanCodeFromV1 user_id, (err, planCode) -> - callback err, SubscriptionUpdater._planCodeToFeatures(planCode) - - _mergeFeatures: (featuresA, featuresB) -> - features = Object.assign({}, featuresA) - for key, value of featuresB - # Special merging logic for non-boolean features - if key == 'compileGroup' - if features['compileGroup'] == 'priority' or featuresB['compileGroup'] == 'priority' - features['compileGroup'] = 'priority' - else - features['compileGroup'] = 'standard' - else if key == 'collaborators' - if features['collaborators'] == -1 or featuresB['collaborators'] == -1 - features['collaborators'] = -1 - else - features['collaborators'] = Math.max( - features['collaborators'] or 0, - featuresB['collaborators'] or 0 - ) - else if key == 'compileTimeout' - features['compileTimeout'] = Math.max( - features['compileTimeout'] or 0, - featuresB['compileTimeout'] or 0 - ) - else - # Boolean keys, true is better - features[key] = features[key] or featuresB[key] - return features - - _subscriptionToFeatures: (subscription) -> - SubscriptionUpdater._planCodeToFeatures(subscription?.planCode) - - _planCodeToFeatures: (planCode) -> - if !planCode? - return {} - plan = PlansLocator.findLocalPlanInSettings planCode - if !plan? - return {} - else - return plan.features \ No newline at end of file diff --git a/services/web/test/acceptance/config/settings.test.coffee b/services/web/test/acceptance/config/settings.test.coffee index 1bcb7426ff..3d665f8a54 100644 --- a/services/web/test/acceptance/config/settings.test.coffee +++ b/services/web/test/acceptance/config/settings.test.coffee @@ -1,10 +1,4 @@ module.exports = - apis: - v1: - url: "http://localhost:5000" - user: 'overleaf' - pass: 'password' - enableSubscriptions: true features: features = diff --git a/services/web/test/unit/coffee/Subscription/FeaturesUpdaterTests.coffee b/services/web/test/unit/coffee/Subscription/FeaturesUpdaterTests.coffee new file mode 100644 index 0000000000..c8f77bfd40 --- /dev/null +++ b/services/web/test/unit/coffee/Subscription/FeaturesUpdaterTests.coffee @@ -0,0 +1,173 @@ +SandboxedModule = require('sandboxed-module') +should = require('chai').should() +expect = require('chai').expect +sinon = require 'sinon' +modulePath = "../../../../app/js/Features/Subscription/FeaturesUpdater" +assert = require("chai").assert +ObjectId = require('mongoose').Types.ObjectId + +describe "FeaturesUpdater", -> + + beforeEach -> + @user_id = ObjectId().toString() + + @FeaturesUpdater = SandboxedModule.require modulePath, requires: + './UserFeaturesUpdater': @UserFeaturesUpdater = {} + './SubscriptionLocator': @SubscriptionLocator = {} + './PlansLocator': @PlansLocator = {} + "logger-sharelatex": log:-> + 'settings-sharelatex': @Settings = {} + "../Referal/ReferalFeatures" : @ReferalFeatures = {} + "./V1SubscriptionManager": @V1SubscriptionManager = {} + + describe "refreshFeatures", -> + beforeEach -> + @UserFeaturesUpdater.updateFeatures = sinon.stub().yields() + @FeaturesUpdater._getIndividualFeatures = sinon.stub().yields(null, { 'individual': 'features' }) + @FeaturesUpdater._getGroupFeatureSets = sinon.stub().yields(null, [{ 'group': 'features' }, { 'group': 'features2' }]) + @FeaturesUpdater._getV1Features = sinon.stub().yields(null, { 'v1': 'features' }) + @ReferalFeatures.getBonusFeatures = sinon.stub().yields(null, { 'bonus': 'features' }) + @FeaturesUpdater._mergeFeatures = sinon.stub().returns({'merged': 'features'}) + @callback = sinon.stub() + @FeaturesUpdater.refreshFeatures @user_id, @callback + + it "should get the individual features", -> + @FeaturesUpdater._getIndividualFeatures + .calledWith(@user_id) + .should.equal true + + it "should get the group features", -> + @FeaturesUpdater._getGroupFeatureSets + .calledWith(@user_id) + .should.equal true + + it "should get the v1 features", -> + @FeaturesUpdater._getV1Features + .calledWith(@user_id) + .should.equal true + + it "should get the bonus features", -> + @ReferalFeatures.getBonusFeatures + .calledWith(@user_id) + .should.equal true + + it "should merge from the default features", -> + @FeaturesUpdater._mergeFeatures.calledWith(@Settings.defaultFeatures).should.equal true + + it "should merge the individual features", -> + @FeaturesUpdater._mergeFeatures.calledWith(sinon.match.any, { 'individual': 'features' }).should.equal true + + it "should merge the group features", -> + @FeaturesUpdater._mergeFeatures.calledWith(sinon.match.any, { 'group': 'features' }).should.equal true + @FeaturesUpdater._mergeFeatures.calledWith(sinon.match.any, { 'group': 'features2' }).should.equal true + + it "should merge the v1 features", -> + @FeaturesUpdater._mergeFeatures.calledWith(sinon.match.any, { 'v1': 'features' }).should.equal true + + it "should merge the bonus features", -> + @FeaturesUpdater._mergeFeatures.calledWith(sinon.match.any, { 'bonus': 'features' }).should.equal true + + it "should update the user with the merged features", -> + @UserFeaturesUpdater.updateFeatures + .calledWith(@user_id, {'merged': 'features'}) + .should.equal true + + describe "_mergeFeatures", -> + it "should prefer priority over standard for compileGroup", -> + expect(@FeaturesUpdater._mergeFeatures({ + compileGroup: 'priority' + }, { + compileGroup: 'standard' + })).to.deep.equal({ + compileGroup: 'priority' + }) + expect(@FeaturesUpdater._mergeFeatures({ + compileGroup: 'standard' + }, { + compileGroup: 'priority' + })).to.deep.equal({ + compileGroup: 'priority' + }) + expect(@FeaturesUpdater._mergeFeatures({ + compileGroup: 'priority' + }, { + compileGroup: 'priority' + })).to.deep.equal({ + compileGroup: 'priority' + }) + expect(@FeaturesUpdater._mergeFeatures({ + compileGroup: 'standard' + }, { + compileGroup: 'standard' + })).to.deep.equal({ + compileGroup: 'standard' + }) + + it "should prefer -1 over any other for collaborators", -> + expect(@FeaturesUpdater._mergeFeatures({ + collaborators: -1 + }, { + collaborators: 10 + })).to.deep.equal({ + collaborators: -1 + }) + expect(@FeaturesUpdater._mergeFeatures({ + collaborators: 10 + }, { + collaborators: -1 + })).to.deep.equal({ + collaborators: -1 + }) + expect(@FeaturesUpdater._mergeFeatures({ + collaborators: 4 + }, { + collaborators: 10 + })).to.deep.equal({ + collaborators: 10 + }) + + it "should prefer the higher of compileTimeout", -> + expect(@FeaturesUpdater._mergeFeatures({ + compileTimeout: 20 + }, { + compileTimeout: 10 + })).to.deep.equal({ + compileTimeout: 20 + }) + expect(@FeaturesUpdater._mergeFeatures({ + compileTimeout: 10 + }, { + compileTimeout: 20 + })).to.deep.equal({ + compileTimeout: 20 + }) + + it "should prefer the true over false for other keys", -> + expect(@FeaturesUpdater._mergeFeatures({ + github: true + }, { + github: false + })).to.deep.equal({ + github: true + }) + expect(@FeaturesUpdater._mergeFeatures({ + github: false + }, { + github: true + })).to.deep.equal({ + github: true + }) + expect(@FeaturesUpdater._mergeFeatures({ + github: true + }, { + github: true + })).to.deep.equal({ + github: true + }) + expect(@FeaturesUpdater._mergeFeatures({ + github: false + }, { + github: false + })).to.deep.equal({ + github: false + }) diff --git a/services/web/test/unit/coffee/Subscription/SubscriptionControllerTests.coffee b/services/web/test/unit/coffee/Subscription/SubscriptionControllerTests.coffee index 47301ecf7c..04888e2dd7 100644 --- a/services/web/test/unit/coffee/Subscription/SubscriptionControllerTests.coffee +++ b/services/web/test/unit/coffee/Subscription/SubscriptionControllerTests.coffee @@ -75,7 +75,7 @@ describe "SubscriptionController", -> "./SubscriptionDomainHandler":@SubscriptionDomainHandler "../User/UserGetter": @UserGetter "./RecurlyWrapper": @RecurlyWrapper = {} - "./SubscriptionUpdater": @SubscriptionUpdater = {} + "./FeaturesUpdater": @FeaturesUpdater = {} @res = new MockResponse() diff --git a/services/web/test/unit/coffee/Subscription/SubscriptionUpdaterTests.coffee b/services/web/test/unit/coffee/Subscription/SubscriptionUpdaterTests.coffee index 71ae6346ce..dd2afad56b 100644 --- a/services/web/test/unit/coffee/Subscription/SubscriptionUpdaterTests.coffee +++ b/services/web/test/unit/coffee/Subscription/SubscriptionUpdaterTests.coffee @@ -67,9 +67,7 @@ describe "SubscriptionUpdater", -> './PlansLocator': @PlansLocator "logger-sharelatex": log:-> 'settings-sharelatex': @Settings - "../Referal/ReferalFeatures" : @ReferalFeatures - '../../infrastructure/Modules': @Modules - "./V1SubscriptionManager": @V1SubscriptionManager = {} + "./FeaturesUpdater": @FeaturesUpdater = {} describe "syncSubscription", -> @@ -100,7 +98,7 @@ describe "SubscriptionUpdater", -> describe "_updateSubscriptionFromRecurly", -> beforeEach -> - @SubscriptionUpdater.refreshFeatures = sinon.stub().callsArgWith(1) + @FeaturesUpdater.refreshFeatures = sinon.stub().callsArgWith(1) it "should update the subscription with token etc when not expired", (done)-> @SubscriptionUpdater._updateSubscriptionFromRecurly @recurlySubscription, @subscription, (err)=> @@ -111,7 +109,7 @@ describe "SubscriptionUpdater", -> assert.equal(@subscription.freeTrial.expiresAt, undefined) assert.equal(@subscription.freeTrial.planCode, undefined) @subscription.save.called.should.equal true - @SubscriptionUpdater.refreshFeatures.calledWith(@adminUser._id).should.equal true + @FeaturesUpdater.refreshFeatures.calledWith(@adminUser._id).should.equal true done() it "should remove the recurlySubscription_id when expired", (done)-> @@ -120,15 +118,15 @@ describe "SubscriptionUpdater", -> @SubscriptionUpdater._updateSubscriptionFromRecurly @recurlySubscription, @subscription, (err)=> assert.equal(@subscription.recurlySubscription_id, undefined) @subscription.save.called.should.equal true - @SubscriptionUpdater.refreshFeatures.calledWith(@adminUser._id).should.equal true + @FeaturesUpdater.refreshFeatures.calledWith(@adminUser._id).should.equal true done() it "should update all the users features", (done)-> @SubscriptionUpdater._updateSubscriptionFromRecurly @recurlySubscription, @subscription, (err)=> - @SubscriptionUpdater.refreshFeatures.calledWith(@adminUser._id).should.equal true - @SubscriptionUpdater.refreshFeatures.calledWith(@allUserIds[0]).should.equal true - @SubscriptionUpdater.refreshFeatures.calledWith(@allUserIds[1]).should.equal true - @SubscriptionUpdater.refreshFeatures.calledWith(@allUserIds[2]).should.equal true + @FeaturesUpdater.refreshFeatures.calledWith(@adminUser._id).should.equal true + @FeaturesUpdater.refreshFeatures.calledWith(@allUserIds[0]).should.equal true + @FeaturesUpdater.refreshFeatures.calledWith(@allUserIds[1]).should.equal true + @FeaturesUpdater.refreshFeatures.calledWith(@allUserIds[2]).should.equal true done() it "should set group to true and save how many members can be added to group", (done)-> @@ -155,6 +153,9 @@ describe "SubscriptionUpdater", -> done() describe "addUserToGroup", -> + beforeEach -> + @FeaturesUpdater.refreshFeatures = sinon.stub().callsArgWith(1) + it "should add the users id to the group as a set", (done)-> @SubscriptionUpdater.addUserToGroup @adminUser._id, @otherUserId, => searchOps = @@ -166,12 +167,12 @@ describe "SubscriptionUpdater", -> it "should update the users features", (done)-> @SubscriptionUpdater.addUserToGroup @adminUser._id, @otherUserId, => - @UserFeaturesUpdater.updateFeatures.calledWith(@otherUserId, @subscription.planCode).should.equal true + @FeaturesUpdater.refreshFeatures.calledWith(@otherUserId).should.equal true done() describe "removeUserFromGroup", -> beforeEach -> - @SubscriptionUpdater.refreshFeatures = sinon.stub().callsArgWith(1) + @FeaturesUpdater.refreshFeatures = sinon.stub().callsArgWith(1) it "should pull the users id from the group", (done)-> @SubscriptionUpdater.removeUserFromGroup @adminUser._id, @otherUserId, => @@ -184,160 +185,9 @@ describe "SubscriptionUpdater", -> it "should update the users features", (done)-> @SubscriptionUpdater.removeUserFromGroup @adminUser._id, @otherUserId, => - @SubscriptionUpdater.refreshFeatures.calledWith(@otherUserId).should.equal true + @FeaturesUpdater.refreshFeatures.calledWith(@otherUserId).should.equal true done() - describe "refreshFeatures", -> - beforeEach -> - @SubscriptionUpdater._getIndividualFeatures = sinon.stub().yields(null, { 'individual': 'features' }) - @SubscriptionUpdater._getGroupFeatureSets = sinon.stub().yields(null, [{ 'group': 'features' }, { 'group': 'features2' }]) - @SubscriptionUpdater._getV1Features = sinon.stub().yields(null, { 'v1': 'features' }) - @ReferalFeatures.getBonusFeatures = sinon.stub().yields(null, { 'bonus': 'features' }) - @SubscriptionUpdater._mergeFeatures = sinon.stub().returns({'merged': 'features'}) - @callback = sinon.stub() - @SubscriptionUpdater.refreshFeatures @user_id, @callback - - it "should get the individual features", -> - @SubscriptionUpdater._getIndividualFeatures - .calledWith(@user_id) - .should.equal true - - it "should get the group features", -> - @SubscriptionUpdater._getGroupFeatureSets - .calledWith(@user_id) - .should.equal true - - it "should get the v1 features", -> - @SubscriptionUpdater._getV1Features - .calledWith(@user_id) - .should.equal true - - it "should get the bonus features", -> - @ReferalFeatures.getBonusFeatures - .calledWith(@user_id) - .should.equal true - - it "should merge from the default features", -> - @SubscriptionUpdater._mergeFeatures.calledWith(@Settings.defaultFeatures).should.equal true - - it "should merge the individual features", -> - @SubscriptionUpdater._mergeFeatures.calledWith(sinon.match.any, { 'individual': 'features' }).should.equal true - - it "should merge the group features", -> - @SubscriptionUpdater._mergeFeatures.calledWith(sinon.match.any, { 'group': 'features' }).should.equal true - @SubscriptionUpdater._mergeFeatures.calledWith(sinon.match.any, { 'group': 'features2' }).should.equal true - - it "should merge the v1 features", -> - @SubscriptionUpdater._mergeFeatures.calledWith(sinon.match.any, { 'v1': 'features' }).should.equal true - - it "should merge the bonus features", -> - @SubscriptionUpdater._mergeFeatures.calledWith(sinon.match.any, { 'bonus': 'features' }).should.equal true - - it "should update the user with the merged features", -> - @UserFeaturesUpdater.updateFeatures - .calledWith(@user_id, {'merged': 'features'}) - .should.equal true - - describe "_mergeFeatures", -> - it "should prefer priority over standard for compileGroup", -> - expect(@SubscriptionUpdater._mergeFeatures({ - compileGroup: 'priority' - }, { - compileGroup: 'standard' - })).to.deep.equal({ - compileGroup: 'priority' - }) - expect(@SubscriptionUpdater._mergeFeatures({ - compileGroup: 'standard' - }, { - compileGroup: 'priority' - })).to.deep.equal({ - compileGroup: 'priority' - }) - expect(@SubscriptionUpdater._mergeFeatures({ - compileGroup: 'priority' - }, { - compileGroup: 'priority' - })).to.deep.equal({ - compileGroup: 'priority' - }) - expect(@SubscriptionUpdater._mergeFeatures({ - compileGroup: 'standard' - }, { - compileGroup: 'standard' - })).to.deep.equal({ - compileGroup: 'standard' - }) - - it "should prefer -1 over any other for collaborators", -> - expect(@SubscriptionUpdater._mergeFeatures({ - collaborators: -1 - }, { - collaborators: 10 - })).to.deep.equal({ - collaborators: -1 - }) - expect(@SubscriptionUpdater._mergeFeatures({ - collaborators: 10 - }, { - collaborators: -1 - })).to.deep.equal({ - collaborators: -1 - }) - expect(@SubscriptionUpdater._mergeFeatures({ - collaborators: 4 - }, { - collaborators: 10 - })).to.deep.equal({ - collaborators: 10 - }) - - it "should prefer the higher of compileTimeout", -> - expect(@SubscriptionUpdater._mergeFeatures({ - compileTimeout: 20 - }, { - compileTimeout: 10 - })).to.deep.equal({ - compileTimeout: 20 - }) - expect(@SubscriptionUpdater._mergeFeatures({ - compileTimeout: 10 - }, { - compileTimeout: 20 - })).to.deep.equal({ - compileTimeout: 20 - }) - - it "should prefer the true over false for other keys", -> - expect(@SubscriptionUpdater._mergeFeatures({ - github: true - }, { - github: false - })).to.deep.equal({ - github: true - }) - expect(@SubscriptionUpdater._mergeFeatures({ - github: false - }, { - github: true - })).to.deep.equal({ - github: true - }) - expect(@SubscriptionUpdater._mergeFeatures({ - github: true - }, { - github: true - })).to.deep.equal({ - github: true - }) - expect(@SubscriptionUpdater._mergeFeatures({ - github: false - }, { - github: false - })).to.deep.equal({ - github: false - }) - describe "deleteSubscription", -> beforeEach (done) -> @subscription_id = ObjectId().toString() @@ -347,7 +197,7 @@ describe "SubscriptionUpdater", -> member_ids: [ ObjectId(), ObjectId(), ObjectId() ] } @SubscriptionLocator.getSubscription = sinon.stub().yields(null, @subscription) - @SubscriptionUpdater.refreshFeatures = sinon.stub().yields() + @FeaturesUpdater.refreshFeatures = sinon.stub().yields() @SubscriptionUpdater.deleteSubscription @subscription_id, done it "should look up the subscription", -> @@ -361,12 +211,12 @@ describe "SubscriptionUpdater", -> .should.equal true it "should downgrade the admin_id", -> - @SubscriptionUpdater.refreshFeatures + @FeaturesUpdater.refreshFeatures .calledWith(@subscription.admin_id) .should.equal true it "should downgrade all of the members", -> for user_id in @subscription.member_ids - @SubscriptionUpdater.refreshFeatures + @FeaturesUpdater.refreshFeatures .calledWith(user_id) .should.equal true