UNPKG

@luminati-io/luminati-proxy

Version:

A configurable local proxy for brightdata.com

764 lines (762 loc) 33 kB
// LICENSE_CODE ZON ISC 'use strict'; /*jslint node:true, mocha:true*/ const assert = require('assert'); const {Netmask} = require('netmask'); const sinon = require('sinon'); const ssl = require('../lib/ssl.js'); const etask = require('../util/etask.js'); const {ms} = require('../util/date.js'); const lpm_request = require('../util/lpm_request.js'); const Server = require('../lib/server.js'); const Manager = require('../lib/manager.js'); const {Timeline} = require('../lib/util.js'); const common = require('./common.js'); const {http_proxy, smtp_test_server, http_ping, init_lum} = common; const test_url = {http: 'http://lumtest.com/test', https: 'https://lumtest.com/test'}; const TEST_SMTP_PORT = 10025; describe('rules', ()=>{ let proxy, ping, smtp, sandbox, lum, l; before(etask._fn(function*before(_this){ _this.timeout(30000); console.log('Start prep', new Date()); yield ssl.load_ca(new Manager({})); proxy = yield http_proxy(); smtp = yield smtp_test_server(TEST_SMTP_PORT); ping = yield http_ping(); console.log('End prep', new Date()); })); after('after all', etask._fn(function*after(_this){ _this.timeout(3000); if (proxy) yield proxy.stop(); proxy = null; smtp.close(); if (ping) yield ping.stop(); ping = null; })); beforeEach(()=>{ Server.session_to_ip = {}; Server.last_ip = new Netmask('1.1.1.0'); common.last_ip = new Netmask('1.1.1.0'); sandbox = sinon.createSandbox(); proxy.fake = true; proxy.connection = null; proxy.history = []; proxy.full_history = []; smtp.silent = false; ping.history = []; lum = init_lum(proxy); }); afterEach('after each', ()=>etask(function*(){ if (!l) return; yield l.stop(true); l = null; sandbox.verifyAndRestore(); })); const get_retry_rule = (retry_port=24001)=>({ action: {retry: true, retry_port}, action_type: 'retry_port', status: '200', }); const make_cred_spy = _l=>sinon.spy(_l, 'get_req_cred'); const get_username = spy=>spy.returnValues[0].username; const inject_headers = (li, ip, ip_alt)=>{ ip = ip||'ip'; let call_count = 0; const handle_proxy_resp_org = li.handle_proxy_resp.bind(li); return sinon.stub(li, 'handle_proxy_resp').callsFake((...args)=> _res=>{ const ip_inj = ip_alt && call_count++%2 ? ip_alt : ip; _res.headers['x-luminati-ip'] = ip_inj; return handle_proxy_resp_org(...args)(_res); }); }; it('check Trigger', ()=>{ const Trigger = require('../lib/rules').t.Trigger; const t = (code, _url, expected)=>{ const cond = new Trigger({trigger_code: code}); assert.equal(cond.test({url: _url}), expected); }; t('function trigger(opt){ return false; }', '', false); t('function trigger(opt){ return false; }', 'http://google.com', false); t('function trigger(opt){ return true; }', '', true); t('function trigger(opt){ return true; }', 'http://google.com', true); t(`function trigger(opt){ return opt.url.includes('facebook.com'); }`, '', false); t(`function trigger(opt){ return opt.url.includes('facebook.com'); }`, 'http://google.com', false); t(`function trigger(opt){ return opt.url.includes('facebook.com'); }`, 'http://facebook.com', true); t('function trigger(opt){ return true; }', 'http://google.com', true); t('function trigger(opt){ throw Error(\'error\') }', '', false); }); it('check can_retry', ()=>etask(function*(){ l = yield lum({rules: []}); const t = (req, rule, expected)=>{ const r = l.rules.can_retry(req, rule); assert.equal(r, expected); }; t({retry: 0}, {test: true}, false); t({retry: 0}, {retry: 1}, true); t({retry: 0}, {retry_port: 24001}, true); t({retry: 5}, {retry: 1}, false); })); it('check retry', ()=>etask(function*(){ l = yield lum({rules: []}); const _req = {ctx: {response: {}, url: 'lumtest.com', log: l.log, proxies: []}}; let called = false; l.on('retry', opt=>{ assert.deepEqual(opt.req, _req); called = true; }); l.rules.retry(_req, {}, {}, {retry_port: l.port}); assert.equal(_req.retry, 1); assert.ok(called); l.rules.retry(_req, {}, {}, {retry_port: l.port}); assert.equal(_req.retry, 2); })); it('check can_retry', ()=>etask(function*(){ l = yield lum({rules: []}); assert.ok(!l.rules.can_retry({})); assert.ok(l.rules.can_retry({retry: 2}, {retry: 5})); assert.ok(!l.rules.can_retry({retry: 5})); assert.ok(l.rules.can_retry({retry: 2}, {refresh_ip: false, retry: 3})); assert.ok(!l.rules.can_retry({retry: 2}, {refresh_ip: false, retry: true})); assert.ok(!l.rules.can_retry({retry: 2}, {refresh_ip: true, retry: true})); assert.ok(l.rules.can_retry({retry: 1}, {retry_port: 24001, retry: true})); })); it('check post_need_body', ()=>etask(function*(){ l = yield lum({rules: [{url: 'test'}]}); const t = (req, expected)=>etask(function*(){ const r = yield l.rules.post_need_body(req); assert.equal(r, expected); }); yield t({ctx: {url: 'invalid'}}, false); yield t({ctx: {url: 'test'}}, false); yield l.stop(true); l = yield lum({rules: [{type: 'after_body', body: '1', url: 'test'}]}); yield t({ctx: {url: 'test'}}, true); })); it('check post', ()=>etask(function*(){ l = yield lum({rules: [{url: 'test'}]}); const t = (req, _res, expected)=>etask(function*(){ req.ctx = Object.assign({skip_rule: ()=>false}, req.ctx); const r = yield l.rules.post(req, {}, {}, _res||{}); assert.equal(r, expected); }); yield t({ctx: {h_context: 'STATUS CHECK'}}); yield t({ctx: {url: 'invalid'}}); sinon.stub(l.rules, 'action').returns(true); yield t({ctx: {url: 'test'}}, {}, undefined); })); describe('action', ()=>{ it('retry_port should update context port', ()=>etask(function*(){ l = yield lum({ rules: [{action: {retry_port: 24001}, status: '200'}], }); const l2 = yield lum({port: 24001}); let p1, p2; l.on('retry', opt=>{ p1 = opt.req.ctx.port; l2.lpm_request(opt.req, opt.res, opt.head, opt.post); p2 = opt.req.ctx.port; }); yield l.test({fake: 1, no_usage: true}); assert.notEqual(p1, p2); l2.stop(true); })); it('refresh_ip', ()=>etask(function*(){ l = yield lum({rules: []}); sinon.stub(l.rules, 'can_retry').returns(true); sinon.stub(l.rules, 'retry'); const ref_stub = sinon.stub(l, 'refresh_ip').returns('test'); const req = {ctx: {}}; const opt = {_res: {hola_headers: {'x-luminati-ip': 'ip'}}}; const r = yield l.rules.action(req, {}, {}, {action: {refresh_ip: true}}, opt); assert.ok(r); assert.ok(ref_stub.called); assert.equal(l.refresh_task, 'test'); })); describe('ban_ip', ()=>{ it('ban_ip', ()=>etask(function*(){ l = yield lum({rules: []}); sinon.stub(l.rules, 'can_retry').returns(false); const add_stub = sinon.stub(l, 'banip'); const req = {ctx: {}}; const opt = {_res: { hola_headers: {'x-luminati-ip': '1.2.3.4'}}}; const retried = yield l.rules.action(req, {}, {}, {action: {ban_ip: 1000}}, opt); assert.ok(!retried); assert.ok(add_stub.called); })); const t = (name, req)=>it(name, ()=>etask(function*(){ proxy.fake = true; sandbox.stub(Server, 'get_random_ip').returns('1.1.1.1'); sandbox.stub(common, 'get_random_ip').returns('1.1.1.1'); l = yield lum({rules: [{ action: {ban_ip: 0}, action_type: 'ban_ip', status: '200', trigger_type: 'status', }]}); l.on('retry', opt=>{ l.lpm_request(opt.req, opt.res, opt.head, opt.post); }); for (let i=0; i<2; i++) { let w = etask.wait(); l.on('usage', data=>w.return(data)); let res = yield l.test(req); let usage = yield w; assert.equal(res.statusCode, 200); assert.deepStrictEqual(usage.rules, [{ action: {ban_ip: 0}, action_type: 'ban_ip', status: '200', trigger_type: 'status', type: 'after_hdr'}]); } })); t('ban_ip http', {url: test_url.http}); t('ban_ip https', {url: test_url.https}); }); describe('request_url', ()=>{ let req, req_stub; beforeEach(()=>etask(function*(){ l = yield lum({rules: []}); req = {ctx: {}}; req_stub = sinon.stub(lpm_request, 'request').callsFake( ()=>({on: ()=>null, end: ()=>null})); })); afterEach(()=>{ req_stub.restore(); }); it('does nothing on invalid urls', ()=>etask(function*(){ const r = yield l.rules.action(req, {}, {}, {action: {request_url: {url: 'blabla'}}}, {}); assert.ok(!r); sinon.assert.notCalled(req_stub); })); it('sends request with http', ()=>etask(function*(){ const url = 'http://lumtest.com'; const r = yield l.rules.action(req, {}, {}, {action: {request_url: {url}}}, {}); assert.ok(!r); sinon.assert.calledWith(req_stub, sinon.match({url})); })); it('sends request with https', ()=>etask(function*(){ const url = 'https://lumtest.com'; const r = yield l.rules.action(req, {}, {}, {action: {request_url: {url}}}, {}); assert.ok(!r); sinon.assert.calledWith(req_stub, sinon.match({url})); })); it('sends request with custom method', ()=>etask(function*(){ const url = 'http://lumtest.com'; const r = yield l.rules.action(req, {}, {}, {action: {request_url: {url, method: 'POST'}}}, {}); assert.ok(!r); sinon.assert.calledWith(req_stub, sinon.match({url})); })); it('sends request with custom payload', ()=>etask(function*(){ const url = 'http://lumtest.com'; const payload = {a: 1, b: 'str'}; const payload_str = JSON.stringify(payload); const rule = {url, method: 'POST', payload}; const r = yield l.rules.action(req, {}, {}, {action: {request_url: rule}}, {}); assert.ok(!r); const headers = { 'Content-Type': 'application/json', 'Content-Length': Buffer.byteLength(payload_str), }; sinon.assert.calledWith(req_stub, sinon.match({ url, method: 'POST', headers, body: payload_str })); })); it('does not send payload in GET requests', ()=> etask(function*(){ const url = 'http://lumtest.com'; const payload = {a: 1, b: 'str'}; const rule = {url, method: 'GET', payload}; const r = yield l.rules.action(req, {}, {}, {action: {request_url: rule}}, {}); assert.ok(!r); sinon.assert.calledWith(req_stub, sinon.match({ url, method: 'GET' })); })); it('sends request with custom payload with IP', ()=> etask(function*(){ const url = 'http://lumtest.com'; const payload = {a: 1, b: '$IP'}, ip = '1.1.1.1'; const actual_payload = {a: 1, b: ip}; const payload_str = JSON.stringify(actual_payload); const rule = {url, method: 'POST', payload}; const r = yield l.rules.action(req, {}, {}, {action: {request_url: rule}}, {_res: {headers: {'x-luminati-ip': ip}}}); assert.ok(!r); const headers = { 'Content-Type': 'application/json', 'Content-Length': Buffer.byteLength(payload_str), }; sinon.assert.calledWith(req_stub, sinon.match({ url, method: 'POST', headers, body: payload_str })); })); }); describe('retry', ()=>{ it('retry should refresh the session', ()=>etask(function*(){ l = yield lum({ pool_size: 1, rules: [{action: {retry: true}, status: '200'}], }); l.on('retry', opt=>{ l.lpm_request(opt.req, opt.res, opt.head, opt.post); }); const session_a = l.session_mgr.session; yield l.test({fake: 1}); const session_b = l.session_mgr.session; assert.notEqual(session_a, session_b); })); it('retry should rotate the session if it has ip', ()=>etask( function*(){ l = yield lum({pool_size: 2, ips: ['1.1.1.1', '1.1.1.2'], rules: [ {action: {reserve_session: true}, action_type: 'save_to_pool', status: '201'}, {action: {retry: true}, status: '200'}]}); l.on('retry', opt=>{ l.lpm_request(opt.req, opt.res, opt.head, opt.post); }); const session_a = l.session_mgr.session; yield l.test({fake: 1}); const session_b = l.session_mgr.session; assert.notEqual(session_a, session_b); })); }); describe('waterfall', ()=>{ it('emits usage events once', ()=>etask(function*(){ l = yield lum({rules: [get_retry_rule()], logs: 1}); const l2 = yield lum({port: 24001, logs: 1}); let usage_start_counter = 0; let usage_counter = 0; let usage_abort_counter = 0; l.on('usage_start', ()=>usage_start_counter++); l.on('usage', ()=>usage_counter++); l.on('usage_abort', ()=>usage_abort_counter++); l2.on('usage_start', ()=>usage_start_counter++); l2.on('usage', ()=>usage_counter++); l2.on('usage_abort', ()=>usage_abort_counter++); l.on('retry', opt=>{ l2.lpm_request(opt.req, opt.res, opt.head, opt.post); }); const w = etask.wait(); l2.on('usage', ()=>w.continue()); yield l.test({fake: 1, no_usage: 1}); yield w; l2.stop(true); assert.equal(usage_start_counter, 1); assert.equal(usage_counter, 1); assert.equal(usage_abort_counter, 0); })); }); describe('retry_port combined with unblocker', ()=>{ const has_unblocker_flag = u=>u.includes('-unblocker'); const sessions_are_unique = (...users)=>{ const sess_id = u=>u.match(/(?<=session-)(.*?)(?=$|-)/)[1]; return new Set(users.map(sess_id)).size==users.length; }; it('waterfall to & from ub adjusts unblocker flag correctly', ()=>etask(function*(){ l = yield lum({rules: [get_retry_rule()], unblock: true}); const l2 = yield lum({port: 24001, rules: [get_retry_rule(24002)]}); const l3 = yield lum({port: 24002, unblock: true}); l.on('retry', opt=>{ l2.lpm_request(opt.req, opt.res, opt.head, opt.post); }); l2.on('retry', opt=>{ l3.lpm_request(opt.req, opt.res, opt.head, opt.post); }); const cred_spies = [l, l2, l3].map(make_cred_spy); yield l.test({fake: 1, no_usage: true}); const [u1, u2, u3] = cred_spies.map(get_username); assert.ok(has_unblocker_flag(u1)); assert.ok(!has_unblocker_flag(u2)); assert.ok(has_unblocker_flag(u3)); assert.ok(sessions_are_unique(u1, u2, u3)); l2.stop(true); l3.stop(true); })); it('ub to non-ub, followed by no retry', ()=>etask(function*(){ l = yield lum({rules: [get_retry_rule()]}); const l2 = yield lum({port: 24001, unblock: true}); l.on('retry', opt=>{ l2.lpm_request(opt.req, opt.res, opt.head, opt.post); }); let non_retry_u; l.on('usage', ({username})=>{ non_retry_u = username; }); const cred_spies = [l, l2].map(make_cred_spy); yield l.test({fake: 1, no_usage: true}); const [u1, u2] = cred_spies.map(get_username); assert.ok(!has_unblocker_flag(u1)); assert.ok(has_unblocker_flag(u2)); l.rules.rules.pop(); l.session_mgr.refresh_sessions(); yield l.test({fake: 1}); assert.ok(!has_unblocker_flag(non_retry_u)); assert.ok(sessions_are_unique(u1, non_retry_u)); l2.stop(true); })); it('non-ub to ub, followed by no retry', ()=>etask(function*(){ l = yield lum({rules: [get_retry_rule()], unblock: true}); const l2 = yield lum({port: 24001}); l.on('retry', opt=>{ l2.lpm_request(opt.req, opt.res, opt.head, opt.post); }); let non_retry_u; l.on('usage', ({username})=>{ non_retry_u = username; }); const cred_spies = [l, l2].map(make_cred_spy); yield l.test({fake: 1, no_usage: true}); const [u1, u2] = cred_spies.map(get_username); assert.ok(has_unblocker_flag(u1)); assert.ok(!has_unblocker_flag(u2)); l.rules.rules.pop(); l.session_mgr.refresh_sessions(); yield l.test({fake: 1}); assert.ok(has_unblocker_flag(non_retry_u)); assert.ok(sessions_are_unique(u1, non_retry_u)); l2.stop(true); })); it('waterfall from ub to ub keeps unblocker flag intact', ()=>etask(function*(){ l = yield lum({rules: [get_retry_rule()], unblock: true}); const l2 = yield lum({port: 24001, unblock: true}); l.on('retry', opt=>{ l2.lpm_request(opt.req, opt.res, opt.head, opt.post); }); const cred_spies = [l, l2].map(make_cred_spy); yield l.test({fake: 1, no_usage: true}); const [u1, u2] = cred_spies.map(get_username); assert.ok(has_unblocker_flag(u1)); assert.ok(has_unblocker_flag(u2)); l2.stop(true); })); }); xdescribe('dc pool', ()=>{ it('adds to pool when prefill turned off and gathering', ()=>etask(function*(){ const ips = ['2.3.4.5']; l = yield lum({ rules: [{ action: {reserve_session: true}, action_type: 'save_to_pool', status: '200', }], pool_size: 2, static: true, ips, }); inject_headers(l, '1.2.3.4'); l.mgr.proxies = [{port: 24000, ips}]; sinon.stub(l.mgr.config, 'save'); yield l.test(); assert.ok(l.opt.ips.includes('1.2.3.4')); })); it('does not add to pool when pool is full', ()=>etask(function*(){ const ips = ['2.3.4.5', '3.4.5.6']; l = yield lum({ rules: [{ action: {reserve_session: true}, action_type: 'save_to_pool', status: '200', }], pool_size: 2, static: true, ips, }); inject_headers(l, '1.2.3.4'); l.mgr.proxies = [{port: 24000, ips}]; yield l.test(); assert.ok(!l.opt.ips.includes('1.2.3.4')); })); it('removes from pool on ban', ()=>etask(function*(){ l = yield lum({ rules: [{ action_type: 'ban_ip', status: '200', action: {ban_ip: 0}, }], pool_size: 2, ips: ['1.2.3.4', '2.3.4.5'], }); inject_headers(l, '1.2.3.4'); const stub = sinon.stub(l.mgr.config, 'save'); assert.ok(l.opt.ips.includes('1.2.3.4')); yield l.test(); sinon.assert.calledOnce(stub); assert.ok(!l.opt.ips.includes('1.2.3.4')); })); }); describe('ban_ip per domain', ()=>{ const ban_period = 1000, domain = 'abc.com', ip = '10.0.0.2'; let ban_spy; beforeEach(()=>etask(function*(){ l = yield lum({rules: [{action_type: 'ban_ip_domain', status: '200', action: {ban_ip_domain: ban_period}, trigger_type: 'status', url: domain}]}); ban_spy = sinon.spy(l, 'banip'); })); const t = (name, url, ban_count=0)=>it(name, etask._fn(function*(){ const session = {session: 'sess1'}; const req = {ctx: {url, skip_rule: ()=>false, session}}; yield l.rules.post(req, {}, {}, {status_code: 200, headers: {'x-luminati-ip': ip}}); sinon.assert.callCount(ban_spy, ban_count); if (ban_count) { sinon.assert.calledWith(ban_spy, ip, ban_period, session, domain); } })); t('does not trigger on diff domains', 'http://lumtest.com/test'); t('triggers', `http://${domain}/test`, 1); }); }); describe('pre', ()=>{ it('action null_response', ()=>etask(function*(){ l = yield lum({rules: [{action: {null_response: true}}]}); const _req = {ctx: {response: {}, url: 'lumtest.com', log: l.log, timeline: new Timeline(1), init_stats: ()=>null, }}; const _res = {end: sinon.stub(), write: sinon.stub()}; const r = yield l.rules.pre(_req, _res, {}); assert.equal(r.status_code, 200); assert.equal(r.status_message, 'NULL'); })); it('action direct', ()=>etask(function*(){ l = yield lum({rules: [{url: '', action: {direct: true}}]}); const _req = {ctx: {response: {}, url: 'lumtest.com', log: l.log, timeline: new Timeline(1), init_stats: ()=>null, }}; const _res = {end: sinon.stub(), write: sinon.stub()}; const r = yield l.rules.pre(_req, _res, {}); assert.equal(r, undefined); assert.ok(_req.ctx.is_direct); })); it('action retry_port', ()=>etask(function*(){ l = yield lum({rules: [{action: {retry_port: 1, email: 'test@mail'}}]}); let called = false; l.on('retry', opt=>{ called = true; assert.deepEqual(opt.port, 1); assert.deepEqual(opt.req, _req); assert.deepEqual(opt.res, _res); assert.deepEqual(opt.head, _head); }); const _req = {ctx: { response: {}, url: 'lumtest.com', log: l.log, timeline: new Timeline(1), rule_executed: ()=>0, }}; const _res = {end: sinon.stub(), write: sinon.stub()}; const _head = {}; const r = yield l.rules.pre(_req, _res, _head); assert.ok(called); assert.equal(r, 'switched'); })); it('connection timeout', ()=>etask(function*(){ l = yield lum({rules: [ {action_type: 'retry', min_conn_time: 1, trigger_type: 'min_conn_time', action: {}} ]}); l.on('retry', opt=>{ // XXX: this.continue is not working here this.return(); }); // host which is unabled to connect yield l.test('http://127.0.0.1:3000'); yield this.wait(); })); it('connection timeout trigger suspended', ()=>etask(function*(){ l = yield lum({rules: [ {action_type: 'retry', min_conn_time: 100000, trigger_type: 'min_conn_time', action: {}} ]}); let called; const handle_proxy_resp_org = l.handle_proxy_resp.bind(l); sinon.stub(l, 'handle_proxy_resp').callsFake((...args)=> _res=>{ let req = args[0]; req.min_conn_task.return(); req.min_conn_task = {return(){ called=true; }}; return handle_proxy_resp_org(...args)(_res); }); yield l.test(ping.http.url); assert.ok(called); })); }); describe('call post after pre', ()=>{ const t = action=>it(action, ()=>etask(function*(){ l = yield lum({rules: [{ action: {[action]: true}, url: '.*'}, ]}); yield l.test(ping.http.url); })); t('null_response'); t('bypass_proxy'); t('direct'); it('retry_port', ()=>etask(function*(){ l = yield lum({rules: [{action: {retry: true, retry_port: 24001}}]}); const l2 = yield lum({port: 24001}); let called = false; l.on('retry', opt=>{ called = true; assert.equal(opt.port, 24001); l2.lpm_request(opt.req, opt.res, opt.head, opt.post); }); yield l.test(ping.http.url); assert.ok(called); l2.stop(true); })); }); describe('banip combined with', ()=>{ const get_banip_rule = (t=10)=>({ action: {ban_ip: t*ms.MIN}, action_type: 'ban_ip', status: '200', }); const t_pre = (action, ban)=>it(action, ()=>etask(function*(){ l = yield lum({rules: [{action: {[action]: true}}, get_banip_rule()]}); inject_headers(l); const ban_stub = sinon.stub(l, 'banip'); yield l.test(ping.http.url); assert.equal(ban_stub.called, +ban); })); t_pre('null_response', false); // XXX krzysztof: broken test t_pre('bypass_proxy', false); t_pre('direct', true); // XXX krzysztof: this test is not relevant here // it tests multiple servers, should be moved to manager it('retry_port', ()=>etask(function*(){ l = yield lum({rules: [ {action: {retry_port: 24001}}, get_banip_rule(), ]}); const l2 = yield lum({ port: 24001, rules: [get_banip_rule(30)], }); l.on('retry', opt=>{ l2.lpm_request(opt.req, opt.res, opt.head, opt.post); }); inject_headers(l2); const ban_stub = sinon.stub(l, 'banip'); const ban_stub_l2 = sinon.stub(l2, 'banip'); yield l.test(ping.http.url); sinon.assert.calledWith(ban_stub, 'ip', 600000); sinon.assert.calledWith(ban_stub_l2, 'ip', 1800000); l2.stop(true); })); it('waterfall', ()=>etask(function*(){ l = yield lum({rules: [get_banip_rule(), get_retry_rule()]}); const l2 = yield lum({port: 24001, rules: [get_banip_rule(30)]}); l.on('retry', opt=>{ l2.lpm_request(opt.req, opt.res, opt.head, opt.post); }); const header_stub = inject_headers(l); const header_stub_l2 = inject_headers(l2, 'ip2'); const ban_stub = sinon.stub(l, 'banip'); const ban_stub_l2 = sinon.stub(l2, 'banip'); yield l.test({url: ping.http.url, no_usage: true}); sinon.assert.calledWith(ban_stub, 'ip', 600000); sinon.assert.calledWith(ban_stub_l2, 'ip2', 1800000); header_stub.restore(); header_stub_l2.restore(); inject_headers(l, 'ip3'); inject_headers(l2, 'ip4'); yield l.test({url: ping.http.url, no_usage: true}); sinon.assert.calledWith(ban_stub, 'ip3', 600000); sinon.assert.calledWith(ban_stub_l2, 'ip4', 1800000); l2.stop(true); })); it('waterfall first', ()=>etask(function*(){ l = yield lum({rules: [get_retry_rule(), get_banip_rule()]}); const l2 = yield lum({port: 24001, rules: [get_banip_rule(30)]}); l.on('retry', opt=>{ l2.lpm_request(opt.req, opt.res, opt.head, opt.post); }); inject_headers(l); inject_headers(l2); const ban_stub = sinon.stub(l, 'banip'); const ban_stub_l2 = sinon.stub(l2, 'banip'); yield l.test({url: ping.http.url, no_usage: true}); sinon.assert.calledWith(ban_stub, 'ip', 600000); sinon.assert.calledWith(ban_stub_l2, 'ip', 1800000); l2.stop(true); })); describe('existing session', ()=>{ const prepare_lum = opt=>etask(function*(){ opt = opt||{}; l = yield lum(Object.assign({ rules: [get_banip_rule()], pool_size: 1, sticky_ip: false, }, opt)); }); it('default pool', ()=>etask(function*(){ yield prepare_lum({pool_size: 0}); yield l.test({fake: 1}); const first_session = l.session_mgr.session; yield l.test({fake: 1}); const second_session = l.session_mgr.session; assert.ok(first_session!=second_session); })); it('per machine', ()=>etask(function*(){ yield prepare_lum({session: true, sticky_ip: true}); yield l.test({fake: 1}); const sticky_sessions = l.session_mgr.sticky_sessions; const first_session = Object.values(sticky_sessions)[0]; yield l.test({fake: 1}); const second_session = Object.values(sticky_sessions)[0]; assert.ok(first_session!=second_session); })); }); }); });