launchpad-reviewers team mailing list archive
-
launchpad-reviewers team
-
Mailing list archive
-
Message #23519
[Merge] lp:~cjwatson/launchpad/remove-txlongpoll into lp:launchpad
Colin Watson has proposed merging lp:~cjwatson/launchpad/remove-txlongpoll into lp:launchpad.
Commit message:
Remove txlongpoll.
Requested reviews:
Launchpad code reviewers (launchpad-reviewers)
For more details, see:
https://code.launchpad.net/~cjwatson/launchpad/remove-txlongpoll/+merge/366122
The Launchpad integration for this was never fully rolled out, is broken in some hard-to-fix ways, and is unlikely to be fixed.
--
Your team Launchpad code reviewers is requested to review the proposed merge of lp:~cjwatson/launchpad/remove-txlongpoll into lp:launchpad.
=== modified file 'Makefile'
--- Makefile 2018-06-06 12:46:56 +0000
+++ Makefile 2019-04-16 14:35:10 +0000
@@ -284,7 +284,7 @@
bin/test -f $(TESTFLAGS) $(TESTOPTS)
run: build inplace stop
- bin/run -r librarian,bing-webservice,memcached,rabbitmq,txlongpoll \
+ bin/run -r librarian,bing-webservice,memcached,rabbitmq \
-i $(LPCONFIG)
run-testapp: LPCONFIG=testrunner-appserver
@@ -303,7 +303,7 @@
run_all: build inplace stop
bin/run \
-r librarian,sftp,forker,mailman,codebrowse,bing-webservice,\
- memcached,rabbitmq,txlongpoll -i $(LPCONFIG)
+ memcached,rabbitmq -i $(LPCONFIG)
run_codebrowse: compile
BZR_PLUGIN_PATH=bzrplugins $(PY) scripts/start-loggerhead.py
=== modified file 'configs/development/launchpad-lazr.conf'
--- configs/development/launchpad-lazr.conf 2018-06-14 16:28:45 +0000
+++ configs/development/launchpad-lazr.conf 2019-04-16 14:35:10 +0000
@@ -193,11 +193,6 @@
store_search_url: https://api.snapcraft.io/
tools_source: deb http://ppa.launchpad.net/snappy-dev/snapcraft-daily/ubuntu %(series)s main
-[txlongpoll]
-launch: True
-frontend_port: 22435
-uri: /+longpoll/
-
[rosetta]
global_suggestions_enabled: True
generate_templates: True
=== modified file 'configs/development/local-launchpad-apache'
--- configs/development/local-launchpad-apache 2017-01-10 17:26:29 +0000
+++ configs/development/local-launchpad-apache 2019-04-16 14:35:10 +0000
@@ -32,7 +32,6 @@
SSLCertificateKeyFile /etc/apache2/ssl/launchpad.key
ProxyPreserveHost on
- ProxyPass /+longpoll/ http://localhost:22435/ retry=1
ProxyPass /+combo !
ProxyPass / http://localhost:8086/ retry=1
=== modified file 'configs/testrunner/launchpad-lazr.conf'
--- configs/testrunner/launchpad-lazr.conf 2018-05-22 07:53:52 +0000
+++ configs/testrunner/launchpad-lazr.conf 2019-04-16 14:35:10 +0000
@@ -164,11 +164,6 @@
password: none
virtual_host: none
-[txlongpoll]
-launch: False
-frontend_port: none
-uri: none
-
[rosetta]
generate_templates: True
=== modified file 'constraints.txt'
--- constraints.txt 2019-04-08 07:13:18 +0000
+++ constraints.txt 2019-04-16 14:35:10 +0000
@@ -365,8 +365,6 @@
Twisted[conch,tls]==18.4.0
txAMQP==0.6.2
txfixtures==0.4.2
-txlongpoll==0.2.12
-txlongpollfixture==0.1.3
txpkgupload==0.2
typing==3.6.2
unittest2==1.1.0
=== modified file 'database/sampledata/current-dev.sql'
--- database/sampledata/current-dev.sql 2017-12-15 12:15:25 +0000
+++ database/sampledata/current-dev.sql 2019-04-16 14:35:10 +0000
@@ -1,4 +1,4 @@
--- Copyright 2010-2017 Canonical Ltd. This software is licensed under the
+-- Copyright 2010-2019 Canonical Ltd. This software is licensed under the
-- GNU Affero General Public License version 3 (see the file LICENSE).
-- Created using pg_dump (PostgreSQL) 9.3.5
@@ -3825,7 +3825,6 @@
ALTER TABLE featureflag DISABLE TRIGGER ALL;
INSERT INTO featureflag (scope, priority, flag, value, date_modified) VALUES ('default', 0, 'js.combo_loader.enabled', 'true', '2012-05-18 07:34:39.239649');
-INSERT INTO featureflag (scope, priority, flag, value, date_modified) VALUES ('default', 1, 'longpoll.merge_proposals.enabled', 'true', '2012-05-18 07:34:39.239649');
ALTER TABLE featureflag ENABLE TRIGGER ALL;
@@ -3833,7 +3832,6 @@
ALTER TABLE featureflagchangelogentry DISABLE TRIGGER ALL;
-INSERT INTO featureflagchangelogentry (id, date_changed, diff, comment, person) VALUES (1, '2011-10-06 12:44:04.37357', '+longpoll.merge_proposals.enabled default 1 true', 'Enable long-poll for merge proposals in development.', 16);
ALTER TABLE featureflagchangelogentry ENABLE TRIGGER ALL;
=== removed file 'lib/lp/app/javascript/longpoll.js'
--- lib/lp/app/javascript/longpoll.js 2017-07-20 13:29:41 +0000
+++ lib/lp/app/javascript/longpoll.js 1970-01-01 00:00:00 +0000
@@ -1,217 +0,0 @@
-/* Copyright 2011 Canonical Ltd. This software is licensed under the
- * GNU Affero General Public License version 3 (see the file LICENSE).
- *
- * The Launchpad Longpoll module provides the functionnality to deal
- * with longpolling on the JavaScript side.
- *
- * The module method setupLongPollManager is called in every template and
- * the long poll machinery will only be started if LP.cache.longpoll
- * is populated.
- *
- * Usually the only thing you will want to do to use the long polling feature
- * is:
- *
- * a) to make sure LP.cache.longpoll is populated with 'key' and 'uri'.
- *
- * b) to create Javascript handlers for the events which will be fired:
- * - event_key will be fired when the event on the server side is triggered
- * (event_key being the name of the event on the server side).
- * - see below for other events fired by the longpoll machinery.
- *
- * @module longpoll
- */
-YUI.add('lp.app.longpoll', function(Y) {
-
-var namespace = Y.namespace('lp.app.longpoll');
-
-// Event fired when the long polling request starts.
-namespace.longpoll_start_event = 'lp.app.longpoll.start';
-
-// Event fired each time the long polling request fails (to connect or
-// to parse the returned result).
-namespace.longpoll_fail_event = 'lp.app.longpoll.failure';
-
-// Event fired when the delay between each failed connection is set to
-// a long delay (after MAX_SHORT_DELAY_FAILED_ATTEMPTS failed attempts).
-namespace.longpoll_longdelay = 'lp.app.longpoll.longdelay';
-
-// Event fired when the delay between each failed connection is set back
-// to a short delay.
-namespace.longpoll_shortdelay = 'lp.app.longpoll.shortdelay';
-
-namespace._manager = null;
-
-// After MAX_SHORT_DELAY_FAILED_ATTEMPTS failed connections (real failed
-// connections or connection getting an invalid return) separated
-// by SHORT_DELAY (millisec), wait LONG_DELAY (millisec) between
-// each failed connection.
-namespace.MAX_SHORT_DELAY_FAILED_ATTEMPTS = 5;
-namespace.SHORT_DELAY = 1000;
-namespace.LONG_DELAY = 3*60*1000;
-
-/**
- *
- * A Long Poll Manager creates and manages a long polling connexion
- * to the server to fetch events. This class is not directly used
- * but managed through 'setupLongPollManager' which creates and
- * initialises a singleton LongPollManager.
- *
- * @class LongPollManager
- */
-function LongPollManager(config) {
- LongPollManager.superclass.constructor.apply(this, arguments);
-}
-
-LongPollManager.NAME = "longPollManager";
-
-Y.extend(LongPollManager, Y.Base, {
- initializer : function(cfg) {
- this._started = false;
- this._failed_attempts = 0;
- this._repoll = true;
- this._sequence = 0;
- },
-
- setConnectionInfos : function(key, uri) {
- this.key = key;
- this.uri = uri;
- },
-
- _io : function (uri, config) {
- Y.io(uri, config);
- },
-
- successPoll : function (id, response) {
- try {
- var data = Y.JSON.parse(response.responseText);
- if (!data.hasOwnProperty('event_key')) {
- throw new Error("Response has no event_key");
- }
- Y.fire(data.event_key, data);
- return true;
- }
- catch (e) {
- Y.fire(namespace.longpoll_fail_event, e);
- return false;
- }
- },
-
- failurePoll : function () {
- Y.fire(namespace.longpoll_fail_event);
- },
-
- /**
- * Return the delay (milliseconds) to wait before trying to reconnect
- * again after a failed connection.
- *
- * The rationale here is that:
- * 1. We should not try to reconnect instantaneously after a failed
- * connection.
- * 2. After a certain number of failed connections, we should set the
- * delay between two failed connection to a bigger number because
- * the server may be having problems.
- *
- * @method _pollDelay
- */
- _pollDelay : function() {
- this._failed_attempts = this._failed_attempts + 1;
- if (this._failed_attempts >=
- namespace.MAX_SHORT_DELAY_FAILED_ATTEMPTS) {
- Y.fire(namespace.longpoll_longdelay);
- return namespace.LONG_DELAY;
- }
- else {
- return namespace.SHORT_DELAY;
- }
- },
-
- /**
- * Relaunch a connection to the server after a successful or
- * a failed connection.
- *
- * @method repoll
- * @param {Boolean} failed: whether or not the previous connection
- * has failed.
- */
- repoll : function(failed) {
- if (!failed) {
- if (this._failed_attempts >=
- namespace.MAX_SHORT_DELAY_FAILED_ATTEMPTS) {
- Y.fire(namespace.longpoll_shortdelay);
- }
- this._failed_attempts = 0;
- if (this._repoll) {
- this.poll();
- }
- }
- else {
- var delay = this._pollDelay();
- if (this._repoll) {
- Y.later(delay, this, this.poll);
- }
- }
- },
-
- poll : function() {
- var that = this;
- var config = {
- method: "GET",
- sync: false,
- on: {
- failure: function(id, response) {
- if (Y.Lang.isValue(response) &&
- Y.Lang.isValue(response.status) &&
- (response.status === 408 ||
- response.status === 504)) {
- // If the error code is:
- // - 408 Request timeout
- // - 504 Gateway timeout
- // Then ignore the error and start
- // polling again.
- that.repoll(false);
- }
- else {
- that.failurePoll();
- that.repoll(true);
- }
- },
- success: function(id, response) {
- var res = that.successPoll(id, response);
- that.repoll(res);
- }
- }
- };
- this._sequence = this._sequence + 1;
- var queue_uri = this.uri +
- "?uuid=" + this.key +
- "&sequence=" + this._sequence;
- if (!this._started) {
- Y.fire(namespace.longpoll_start_event);
- this._started = true;
- }
- this._io(queue_uri, config);
- }
-});
-
-namespace.LongPollManager = LongPollManager;
-
-namespace.getLongPollManager = function() {
- if (!Y.Lang.isValue(namespace._manager)) {
- namespace._manager = new namespace.LongPollManager();
- }
- return namespace._manager;
-};
-
-namespace.setupLongPollManager = function() {
- if (Y.Object.owns(LP.cache, 'longpoll') &&
- Y.Lang.isValue(LP.cache.longpoll)) {
- var key = LP.cache.longpoll.key;
- var uri = LP.cache.longpoll.uri;
- var longpollmanager = namespace.getLongPollManager();
- longpollmanager.setConnectionInfos(key, uri);
- longpollmanager.poll();
- return longpollmanager;
- }
-};
-
-}, "0.1", {"requires":["base", "event", "json", "io"]});
=== removed file 'lib/lp/app/javascript/tests/test_longpoll.html'
--- lib/lp/app/javascript/tests/test_longpoll.html 2012-10-26 09:54:28 +0000
+++ lib/lp/app/javascript/tests/test_longpoll.html 1970-01-01 00:00:00 +0000
@@ -1,47 +0,0 @@
-<!DOCTYPE html>
-<!--
-Copyright 2012 Canonical Ltd. This software is licensed under the
-GNU Affero General Public License version 3 (see the file LICENSE).
--->
-
-<html>
- <head>
- <title>Test longpoll</title>
-
- <!-- YUI and test setup -->
- <script type="text/javascript"
- src="../../../../../build/js/yui/yui/yui.js">
- </script>
- <link rel="stylesheet"
- href="../../../../../build/js/yui/console/assets/console-core.css" />
- <link rel="stylesheet"
- href="../../../../../build/js/yui/test-console/assets/skins/sam/test-console.css" />
- <link rel="stylesheet"
- href="../../../../../build/js/yui/test/assets/skins/sam/test.css" />
-
- <script type="text/javascript"
- src="../../../../../build/js/lp/app/testing/testrunner.js"></script>
-
- <link rel="stylesheet" href="../../../app/javascript/testing/test.css" />
-
- <!-- Dependencies -->
- <script type="text/javascript"
- src="../../../../../build/js/lp/app/client.js"></script>
-
- <!-- The module under test. -->
- <script type="text/javascript" src="../longpoll.js"></script>
-
- <!-- Placeholder for any css asset for this module. -->
- <!-- <link rel="stylesheet" href="../assets/longpoll-core.css" /> -->
-
- <!-- The test suite. -->
- <script type="text/javascript" src="test_longpoll.js"></script>
-
- </head>
- <body class="yui3-skin-sam">
- <ul id="suites">
- <!-- <li>lp.large_indicator.test</li> -->
- <li>lp.longpoll.test</li>
- </ul>
- </body>
-</html>
=== removed file 'lib/lp/app/javascript/tests/test_longpoll.js'
--- lib/lp/app/javascript/tests/test_longpoll.js 2017-07-24 15:37:03 +0000
+++ lib/lp/app/javascript/tests/test_longpoll.js 1970-01-01 00:00:00 +0000
@@ -1,283 +0,0 @@
-/* Copyright 2011 Canonical Ltd. This software is licensed under the
- * GNU Affero General Public License version 3 (see the file LICENSE). */
-YUI.add('lp.longpoll.test', function (Y) {
- var longpoll = Y.lp.app.longpoll;
-
- var tests = Y.namespace('lp.longpoll.test');
- tests.suite = new Y.Test.Suite('longpoll Tests');
-
- tests.suite.add(new Y.Test.Case({
- name: 'TestLongPollSingleton',
- tearDown: function() {
- // Cleanup the singleton;
- longpoll._manager = null;
- },
-
- testGetSingletonLongPollManager: function() {
- Y.Assert.isNull(longpoll._manager);
- var manager = longpoll.getLongPollManager();
- Y.Assert.isNotNull(longpoll._manager);
- var manager2 = longpoll.getLongPollManager();
- Y.Assert.areSame(manager, manager2);
- },
-
- testInitLongPollManagerNoLongPoll: function() {
- // if LP.cache.longpoll.key is undefined: no longpoll manager
- // is created by setupLongPollManager.
- window.LP = {
- links: {},
- cache: {}
- };
-
- longpoll.setupLongPollManager(true);
- Y.Assert.isNull(longpoll._manager);
- },
-
- testInitLongPollManagerLongPoll: function() {
- window.LP = {
- links: {},
- cache: {
- longpoll: {
- key: 'key',
- uri: '/+longpoll/'
- }
- }
- };
-
- longpoll.setupLongPollManager(true);
- Y.Assert.isNotNull(longpoll._manager);
- }
- }));
-
- tests.suite.add(new Y.Test.Case({
- name: 'TestLongPoll',
-
- setUp: function() {
- var manager = longpoll.getLongPollManager();
- manager._repoll = false;
- this.createBaseLP();
- },
-
- tearDown: function() {
- // Cleanup the singleton;
- longpoll._manager = null;
- },
-
- createBaseLP:function() {
- window.LP = {
- links: {},
- cache: {}
- };
- },
-
- setupLPCache: function() {
- LP.cache.longpoll = {
- key: 'key',
- uri: '/+longpoll/'
- };
- },
-
- setupLongPoll: function(nb_calls) {
- this.setupLPCache();
- return longpoll.setupLongPollManager(true);
- },
-
- testInitLongPollManagerQueueName: function() {
- var manager = this.setupLongPoll();
- Y.Assert.areEqual(LP.cache.longpoll.key, manager.key);
- Y.Assert.areEqual(LP.cache.longpoll.uri, manager.uri);
- Y.Assert.isFalse(Y.Lang.isValue(manager.nb_calls));
- },
-
- testPollStarted: function() {
- var fired = false;
- Y.on(longpoll.longpoll_start_event, function() {
- fired = true;
- });
- this.setupLongPoll();
- Y.Assert.isTrue(fired, "Start event not fired.");
- },
-
- testPollFailure: function() {
- var fired = false;
- Y.on(longpoll.longpoll_fail_event, function() {
- fired = true;
- });
- // Monkeypatch io to simulate failure.
- var manager = longpoll.getLongPollManager();
- manager._io = function(uri, config) {
- config.on.failure();
- };
- this.setupLongPoll();
- Y.Assert.isTrue(fired, "Failure event not fired.");
- },
-
- testSuccessPollInvalidData: function() {
- var manager = longpoll.getLongPollManager();
- var custom_response = "{{";
- var response = {
- responseText: custom_response
- };
- var res = manager.successPoll("2", response);
- Y.Assert.isFalse(res);
- },
-
- testSuccessPollMalformedData: function() {
- var manager = longpoll.getLongPollManager();
- var response = {
- responseText: '{ "something": "6" }'
- };
- var res = manager.successPoll("2", response);
- Y.Assert.isFalse(res);
- },
-
- testSuccessPollWellformedData: function() {
- var manager = longpoll.getLongPollManager();
- var response = {
- responseText: '{ "event_key": "4", "something": "6"}'
- };
- var res = manager.successPoll("2", response);
- Y.Assert.isTrue(res);
- },
-
- testPollDelay: function() {
- // Create event listeners.
- var longdelay_event_fired = false;
- Y.on(longpoll.longpoll_longdelay, function(data) {
- longdelay_event_fired = true;
- });
- var shortdelay_event_fired = false;
- Y.on(longpoll.longpoll_shortdelay, function(data) {
- shortdelay_event_fired = true;
- });
- var manager = longpoll.getLongPollManager();
- // Monkeypatch io to simulate failure.
- manager._io = function(uri, config) {
- config.on.failure();
- };
- Y.Assert.areEqual(0, manager._failed_attempts);
- this.setupLongPoll();
- Y.Assert.areEqual(1, manager._failed_attempts);
- var i, delay;
- for (i=0; i<longpoll.MAX_SHORT_DELAY_FAILED_ATTEMPTS-2; i++) {
- Y.Assert.areEqual(i+1, manager._failed_attempts);
- delay = manager._pollDelay();
- Y.Assert.areEqual(delay, longpoll.SHORT_DELAY);
- }
- // After MAX_SHORT_DELAY_FAILED_ATTEMPTS failed attempts, the
- // delay returned by _pollDelay is LONG_DELAY and
- // longpoll_longdelay is fired.
- Y.Assert.isFalse(longdelay_event_fired);
- delay = manager._pollDelay();
- Y.Assert.isTrue(longdelay_event_fired);
- Y.Assert.areEqual(delay, longpoll.LONG_DELAY);
-
- // Monkeypatch io to simulate success.
- manager._io = function(uri, config) {
- config.on.success();
- };
- // After a success, longpoll.longpoll_shortdelay is fired.
- Y.Assert.isFalse(shortdelay_event_fired);
- delay = manager.poll();
- Y.Assert.isTrue(shortdelay_event_fired);
- },
-
- testPollUriSequence: function() {
- // Each new polling increases the sequence parameter:
- // /+longpoll/?uuid=key&sequence=1
- // /+longpoll/?uuid=key&sequence=2
- // /+longpoll/?uuid=key&sequence=3
- // ..
- var count = 0;
- // Monkeypatch io to simulate failure.
- var manager = longpoll.getLongPollManager();
- manager._io = function(uri, config) {
- Y.Assert.areEqual(
- '/+longpoll/?uuid=key&sequence=' + (count+1),
- uri);
- count = count + 1;
- var response = {
- responseText: '{"i":2}'
- };
- config.on.success(2, response);
- };
- this.setupLongPoll();
- var request;
- for (request=1; request<10; request++) {
- Y.Assert.isTrue(count === request, "Uri not requested.");
- manager.poll();
- }
- },
-
- _testDoesNotFail: function(error_code) {
- // Assert that, when the longpoll request receives an error
- // with code error_code, it is not treated as a failed
- // connection attempt.
- var manager = longpoll.getLongPollManager();
- // Monkeypatch io to simulate a request timeout.
- manager._io = function(uri, config) {
- var response = {status: error_code};
- config.on.failure(4, response);
- };
-
- Y.Assert.areEqual(0, manager._failed_attempts);
- this.setupLongPoll();
- Y.Assert.areEqual(0, manager._failed_attempts);
- },
-
- test408RequestTimeoutHandling: function() {
- this._testDoesNotFail(408);
- },
-
- test504GatewayTimeoutHandling: function() {
- this._testDoesNotFail(504);
- },
-
- testPollPayLoadBad: function() {
- // If a non valid response is returned, longpoll_fail_event
- // is fired.
- var fired = false;
- Y.on(longpoll.longpoll_fail_event, function() {
- fired = true;
- });
- var manager = longpoll.getLongPollManager();
- // Monkeypatch io.
- manager._io = function(uri, config) {
- var response = {
- responseText: "{non valid json"
- };
- config.on.success(2, response);
- };
- this.setupLongPoll();
- Y.Assert.isTrue(fired, "Failure event not fired.");
- },
-
- testPollPayLoadOk: function() {
- // Create a valid message.
- var custom_response = {
- 'event_key': 'my-event',
- 'something': {something_else: 1234}
- };
- var fired = false;
- Y.on(custom_response.event_key, function(data) {
- fired = true;
- Y.Assert.areEqual(data, custom_response);
- });
- var manager = longpoll.getLongPollManager();
- // Monkeypatch io.
- manager._io = function(uri, config) {
- var response = {
- responseText: Y.JSON.stringify(custom_response)
- };
- config.on.success(2, response);
- };
- this.setupLongPoll();
- Y.Assert.isTrue(fired, "Custom event not fired.");
- }
- }));
-
-}, '0.1', {
- requires: [
- 'lp.testing.runner', 'test', 'test-console', 'node-event-simulate',
- 'json', 'lp.app.longpoll']
-});
=== removed directory 'lib/lp/app/longpoll'
=== removed file 'lib/lp/app/longpoll/__init__.py'
--- lib/lp/app/longpoll/__init__.py 2012-02-21 22:46:28 +0000
+++ lib/lp/app/longpoll/__init__.py 1970-01-01 00:00:00 +0000
@@ -1,50 +0,0 @@
-# Copyright 2011-2012 Canonical Ltd. This software is licensed under the
-# GNU Affero General Public License version 3 (see the file LICENSE).
-
-"""Long-poll infrastructure."""
-
-__metaclass__ = type
-__all__ = [
- "emit",
- "subscribe",
- ]
-
-from lazr.restful.utils import get_current_browser_request
-from zope.component import getAdapter
-
-from lp.services.longpoll.interfaces import (
- ILongPollEvent,
- ILongPollSubscriber,
- )
-
-
-def subscribe(target, event_name=u"", request=None):
- """Convenience method to subscribe the current request.
-
- :param target: Something that can be adapted to `ILongPollEvent`.
- :param event_name: The name of the event to subscribe to. This is used to
- look up a named adapter from `target` to `ILongPollEvent`.
- :param request: The request for which to get an `ILongPollSubscriber`. It
- a request is not specified the currently active request is used.
- :return: The `ILongPollEvent` that has been subscribed to.
- """
- event = getAdapter(target, ILongPollEvent, name=event_name)
- if request is None:
- request = get_current_browser_request()
- subscriber = ILongPollSubscriber(request)
- subscriber.subscribe(event)
- return event
-
-
-def emit(source, event_name=u"", **data):
- """Convenience method to emit a message for an event.
-
- :param source: Something that can be adapted to `ILongPollEvent`.
- :param event_name: The name of the event to subscribe to. This is used to
- look up a named adapter from `target` to `ILongPollEvent`.
- :param data: See `ILongPollEvent.emit`.
- :return: The `ILongPollEvent` that has been emitted.
- """
- event = getAdapter(source, ILongPollEvent, name=event_name)
- event.emit(**data)
- return event
=== removed directory 'lib/lp/app/longpoll/tests'
=== removed file 'lib/lp/app/longpoll/tests/__init__.py'
=== removed file 'lib/lp/app/longpoll/tests/test_longpoll.py'
--- lib/lp/app/longpoll/tests/test_longpoll.py 2015-07-09 12:18:51 +0000
+++ lib/lp/app/longpoll/tests/test_longpoll.py 1970-01-01 00:00:00 +0000
@@ -1,121 +0,0 @@
-# Copyright 2011 Canonical Ltd. This software is licensed under the
-# GNU Affero General Public License version 3 (see the file LICENSE).
-
-"""Tests for lp.app.longpoll."""
-
-__metaclass__ = type
-
-from zope.component import (
- adapter,
- getUtility,
- )
-from zope.interface import (
- Attribute,
- implementer,
- Interface,
- )
-
-from lp.app.longpoll import (
- emit,
- subscribe,
- )
-from lp.services.longpoll.interfaces import (
- ILongPollEvent,
- ILongPollSubscriber,
- )
-from lp.services.messaging.interfaces import IMessageSession
-from lp.services.webapp.servers import LaunchpadTestRequest
-from lp.testing import TestCase
-from lp.testing.fixture import ZopeAdapterFixture
-from lp.testing.layers import LaunchpadFunctionalLayer
-
-
-class IFakeObject(Interface):
-
- ident = Attribute("ident")
-
-
-@implementer(IFakeObject)
-class FakeObject:
-
- def __init__(self, ident):
- self.ident = ident
-
-
-@adapter(IFakeObject)
-@implementer(ILongPollEvent)
-class FakeEvent:
-
- def __init__(self, source):
- self.source = source
-
- @property
- def event_key(self):
- return "event-key-%s" % self.source.ident
-
- def emit(self, **data):
- # Don't cargo-cult this; see .adapters.event.LongPollEvent instead.
- session = getUtility(IMessageSession)
- producer = session.getProducer(self.event_key)
- producer.sendNow(data)
-
-
-class TestFunctions(TestCase):
-
- layer = LaunchpadFunctionalLayer
-
- def test_subscribe(self):
- # subscribe() gets the ILongPollEvent for the given target and the
- # ILongPollSubscriber for the given request (or the current request is
- # discovered). It subscribes the latter to the event, then returns the
- # event.
- session = getUtility(IMessageSession)
- request = LaunchpadTestRequest()
- an_object = FakeObject(12345)
- with ZopeAdapterFixture(FakeEvent):
- event = subscribe(an_object, request=request)
- self.assertIsInstance(event, FakeEvent)
- self.assertEqual("event-key-12345", event.event_key)
- session.flush()
- # Emitting an event-key-12345 event will put something on the
- # subscriber's queue.
- event_data = {"1234": 5678}
- event.emit(**event_data)
- subscriber = ILongPollSubscriber(request)
- subscribe_queue = session.getConsumer(subscriber.subscribe_key)
- message = subscribe_queue.receive(timeout=5)
- self.assertEqual(event_data, message)
-
- def test_subscribe_to_named_event(self):
- # When an event_name is given to subscribe(), a named adapter is used
- # to get the ILongPollEvent for the given target.
- request = LaunchpadTestRequest()
- an_object = FakeObject(12345)
- with ZopeAdapterFixture(FakeEvent, name="foo"):
- event = subscribe(an_object, event_name="foo", request=request)
- self.assertIsInstance(event, FakeEvent)
-
- def test_emit(self):
- # emit() gets the ILongPollEvent for the given target and passes the
- # given data to its emit() method. It then returns the event.
- an_object = FakeObject(12345)
- with ZopeAdapterFixture(FakeEvent):
- event = emit(an_object)
- session = getUtility(IMessageSession)
- producer = session.getProducer(event.event_key)
- subscribe_queue = session.getConsumer("whatever")
- producer.associateConsumerNow(subscribe_queue)
- # Emit the event again; the subscribe queue was not associated
- # with the event before now.
- event_data = {"8765": 4321}
- event = emit(an_object, **event_data)
- message = subscribe_queue.receive(timeout=5)
- self.assertEqual(event_data, message)
-
- def test_emit_named_event(self):
- # When an event_name is given to emit(), a named adapter is used to
- # get the ILongPollEvent for the given target.
- an_object = FakeObject(12345)
- with ZopeAdapterFixture(FakeEvent, name="foo"):
- event = emit(an_object, "foo")
- self.assertIsInstance(event, FakeEvent)
=== modified file 'lib/lp/app/templates/base-layout-macros.pt'
--- lib/lp/app/templates/base-layout-macros.pt 2019-01-05 09:54:44 +0000
+++ lib/lp/app/templates/base-layout-macros.pt 2019-04-16 14:35:10 +0000
@@ -120,7 +120,7 @@
//<![CDATA[
LPJS.use('base', 'node', 'console', 'event',
'oop', 'lp', 'lp.app.foldables','lp.app.sorttable',
- 'lp.app.inlinehelp', 'lp.app.links', 'lp.app.longpoll',
+ 'lp.app.inlinehelp', 'lp.app.links',
'lp.bugs.bugtask_index', 'lp.bugs.subscribers',
'lp.app.ellipsis', 'lp.code.branchmergeproposal.diff',
'lp.views.global',
@@ -135,14 +135,6 @@
Y.lp.activate_collapsibles();
Y.lp.app.foldables.activate();
Y.lp.app.links.check_valid_lp_links();
- // Longpolling will only start if
- // LP.cache.longpoll is populated.
- // We use Y.later to work around a Safari/Chrome 'feature':
- // The mouse cursor stays 'busy' until all the requests started during
- // page load are finished. Hence we want the long poll request to start
- // right *after* the page has loaded.
- Y.later(0, Y.lp.app.longpoll, Y.lp.app.longpoll.setupLongPollManager);
-
});
Y.on('lp:context:web_link:changed', function(e) {
=== modified file 'lib/lp/code/browser/branchmergeproposal.py'
--- lib/lp/code/browser/branchmergeproposal.py 2019-01-31 14:45:32 +0000
+++ lib/lp/code/browser/branchmergeproposal.py 2019-04-16 14:35:10 +0000
@@ -1,4 +1,4 @@
-# Copyright 2009-2018 Canonical Ltd. This software is licensed under the
+# Copyright 2009-2019 Canonical Ltd. This software is licensed under the
# GNU Affero General Public License version 3 (see the file LICENSE).
"""Views, navigation and actions for BranchMergeProposals."""
@@ -69,7 +69,6 @@
vocabulary_to_choice_edit_items,
)
from lp.app.browser.tales import DateTimeFormatterAPI
-from lp.app.longpoll import subscribe
from lp.code.adapters.branch import BranchMergeProposalNoPreviewDiffDelta
from lp.code.browser.codereviewcomment import CodeReviewDisplayComment
from lp.code.browser.decorations import DecoratedBranch
@@ -628,9 +627,6 @@
else:
cache.objects['branch_diff_link'] = (
canonical_url(self.context.parent) + '/+diff/')
- if getFeatureFlag("longpoll.merge_proposals.enabled"):
- cache.objects['merge_proposal_event_key'] = subscribe(
- self.context).event_key
@action('Claim', name='claim')
def claim_action(self, action, data):
=== modified file 'lib/lp/code/browser/tests/test_branchmergeproposal.py'
--- lib/lp/code/browser/tests/test_branchmergeproposal.py 2019-01-31 14:21:09 +0000
+++ lib/lp/code/browser/tests/test_branchmergeproposal.py 2019-04-16 14:35:10 +0000
@@ -1,4 +1,4 @@
-# Copyright 2009-2018 Canonical Ltd. This software is licensed under the
+# Copyright 2009-2019 Canonical Ltd. This software is licensed under the
# GNU Affero General Public License version 3 (see the file LICENSE).
"""Unit tests for BranchMergeProposals."""
@@ -1576,26 +1576,6 @@
git_api.notify(bmp.source_git_repository.getInternalPath()))
self.assertTrue(view.pending_diff)
- def test_subscribe_to_merge_proposal_events_flag_disabled(self):
- # If the longpoll.merge_proposals.enabled flag is not enabled the user
- # is *not* subscribed to events relating to the merge proposal.
- bmp = self.factory.makeBranchMergeProposal()
- view = create_initialized_view(bmp, '+index', current_request=True)
- cache = IJSONRequestCache(view.request)
- self.assertNotIn("longpoll", cache.objects)
- self.assertNotIn("merge_proposal_event_key", cache.objects)
-
- def test_subscribe_to_merge_proposal_events_flag_enabled(self):
- # If the longpoll.merge_proposals.enabled flag is enabled the user is
- # subscribed to events relating to the merge proposal.
- bmp = self.factory.makeBranchMergeProposal()
- self.useContext(feature_flags())
- set_feature_flag('longpoll.merge_proposals.enabled', 'enabled')
- view = create_initialized_view(bmp, '+index', current_request=True)
- cache = IJSONRequestCache(view.request)
- self.assertIn("longpoll", cache.objects)
- self.assertIn("merge_proposal_event_key", cache.objects)
-
def test_description_is_meta_description(self):
description = (
"I'd like to make the bmp description appear as the meta "
@@ -2076,20 +2056,6 @@
browser = self.getViewBrowser(bmp)
assert 'unf_pbasyvpgf' in browser.contents
- def test_pending_diff_message_with_longpoll_enabled(self):
- # If the longpoll feature flag is enabled then the message
- # displayed for a pending diff indicates that it'll update
- # automatically. See also
- # lib/lp/code/stories/branches/xx-branchmergeproposals.txt
- self.useContext(feature_flags())
- set_feature_flag('longpoll.merge_proposals.enabled', 'enabled')
- bmp = self.factory.makeBranchMergeProposal()
- browser = self.getViewBrowser(bmp)
- self.assertIn(
- "An updated diff is being calculated and will appear "
- "automatically when ready.",
- browser.contents)
-
def test_short_conversation_comments_not_truncated(self):
"""Short comments should not be truncated."""
comment = self.factory.makeCodeReviewComment(body='x y' * 100)
=== removed file 'lib/lp/code/javascript/branchmergeproposal.updater.js'
--- lib/lp/code/javascript/branchmergeproposal.updater.js 2014-03-31 19:40:35 +0000
+++ lib/lp/code/javascript/branchmergeproposal.updater.js 1970-01-01 00:00:00 +0000
@@ -1,263 +0,0 @@
-/* Copyright 2011 Canonical Ltd. This software is licensed under the
- * GNU Affero General Public License version 3 (see the file LICENSE).
- *
- * Code for updating the diff when a new version is available.
- *
- * @module lp.code.branchmergeproposal.updater
- * @requires node, lp.client
- */
-
-YUI.add('lp.code.branchmergeproposal.updater', function(Y) {
-
-var namespace = Y.namespace('lp.code.branchmergeproposal.updater');
-
-function UpdaterWidget(config) {
- UpdaterWidget.superclass.constructor.apply(this, arguments);
-}
-
-Y.mix(UpdaterWidget, {
-
- NAME: 'updaterWidget',
-
- ATTRS: {
-
- /**
- * The LP client to use. If none is provided, one will be
- * created during initialization.
- *
- * @attribute lp_client
- */
- lp_client: {
- value: null
- },
-
- /**
- * The summary node.
- *
- * @attribute summary_node
- */
- summary_node: {
- value: null,
- writeOnce: "initOnly"
- },
-
- /**
- * Whether or not this MP is still 'pending'.
- *
- * @attribute pending
- * @readOnly
- */
- pending: {
- readOnly: true,
- getter: function() {
- return !Y.Lang.isValue(
- this.get('srcNode').one('.diff-content'));
- }
- },
-
- /**
- * The HTML code for the stats diff.
- *
- * @attribute diff_stats
- */
- diff_stats: {
- getter: function() {
- var summary_node = this.get('summary_node');
- if (!Y.Lang.isValue(summary_node) ||
- !Y.Lang.isValue(summary_node.one(
- '#summary-row-b-diff'))) {
- return null;
- }
- return summary_node.one(
- '#summary-row-b-diff').one('td').get('innerHTML');
- },
- setter: function(value) {
- this._setup_diff_stats_container();
- var container = this.get(
- 'summary_node').one('#summary-row-b-diff').one('td');
- container.set('innerHTML', value);
- }
- }
- }
-
-});
-
-Y.extend(UpdaterWidget, Y.Widget, {
-
- /*
- * The initializer method that is called from the base Plugin class.
- *
- * @method initializer
- * @protected
- */
- initializer: function(cfg){
- // If we have not been provided with a Launchpad Client, then
- // create one now:
- if (null === this.get("lp_client")){
- // Create our own instance of the LP client.
- this.set("lp_client", new Y.lp.client.Launchpad());
- }
- this.set('summary_node', cfg.summary_node);
- },
-
- /*
- * Set the proper icon to indicate the diff is updating.
- *
- * @method set_status_updating
- */
- set_status_updating: function() {
- this.cleanup_status();
- this._set_status('spinner', 'Update in progress.');
- },
-
- /*
- * Set the proper icon to indicate the diff will be updated when the
- * new version is available.
- *
- * @method set_status_longpolling
- */
- set_status_longpolling: function() {
- this.cleanup_status();
- this._set_status(
- 'longpoll_loading',
- 'The diff will be updated as soon as a new version is available.');
- },
-
- /*
- * Set the proper icon to indicate that the diff update is broken.
- *
- * @method set_status_longpollerror
- */
- set_status_longpollerror: function() {
- this.cleanup_status();
- this._set_status(
- 'longpoll_error',
- 'Diff update error, please reload to see the changes.');
- },
-
- /*
- * Add a status image to the diff title.
- *
- * @method _set_status
- */
- _set_status: function(image_name, title) {
- var image = Y.Node.create('<img />')
- .set('src', '/@@/' + image_name)
- .set('title', title);
- this.get('srcNode').one('h2').append(image);
- },
-
- /*
- * Remove the status image to the diff title.
- *
- * @method cleanup_status
- */
- cleanup_status: function() {
- this._setup_diff_container();
- this.get('srcNode').all('h2 img').remove();
- },
-
- /*
- * Add a row in the page summary table to display the diff stats
- * if needed.
- *
- * @method _setup_diff_stats_container
- */
- _setup_diff_stats_container: function() {
- if (!Y.Lang.isValue(this.get('diff_stats'))) {
- var summary_node = this.get('summary_node');
- var diff_stats = Y.Node.create('<tr />')
- .set('id', 'summary-row-b-diff')
- .append(Y.Node.create('<th />')
- .set("text", "Diff against target:"))
- .append(Y.Node.create('<td />'));
- summary_node.one(
- '#summary-row-9-target-branch').insert(diff_stats, 'after');
- }
- },
-
- /*
- * Populate the widget with the required nodes to display the diff
- * if needed.
- *
- * @method _setup_diff_container
- */
- _setup_diff_container: function() {
- if (this.get('pending')) {
- // Cleanup.get('srcNode').
- this.get('srcNode').empty();
- // Create the diff container.
- var review_diff = Y.Node.create('<div />')
- .set('id', 'review-diff')
- .append(Y.Node.create('<h2 />')
- .set("text", "Preview Diff "))
- .append(Y.Node.create('<div />')
- .addClass("diff-navigator"))
- .append(Y.Node.create('<div />')
- .addClass("diff-content"));
- this.get('srcNode').append(review_diff);
- }
- },
-
- /*
- * Update the page diff stats.
- *
- * @method update
- */
- update: function() {
- this.update_stats();
- },
-
- /*
- * Update the diff stats with the last version.
- *
- * @method update_stats
- */
- update_stats: function() {
- var self = this;
- var config = {
- on: {
- success: function(diff_stats) {
- self.set('diff_stats', diff_stats);
- // (re)connect the js scroller link.
- Y.lp.code.branchmergeproposal.reviewcomment.link_scroller(
- '#proposal-summary a.diff-link', '#review-diff');
- var node = self.get('summary_node');
- Y.lp.anim.green_flash({node: node}).run();
- self.fire(self.NAME + '.updated');
- },
- failure: function() {
- var node = self.get('summary_node');
- Y.lp.anim.red_flash({node: node}).run();
- },
- start: function() {
- self.set_status_updating();
- },
- end: function() {
- self.cleanup_status();
- }
- }
- };
- var mp_uri = LP.cache.context.web_link;
- this.get('lp_client').get(mp_uri + "/++diff-stats", config);
- }
-
-});
-
-/*
- * Export UpdaterWidget.
- */
-namespace.UpdaterWidget = UpdaterWidget;
-
-/*
- * Returns true if the event fired means that the preview_diff field of the
- * MP has been updated.
- *
- */
-namespace.is_mp_diff_updated = function(event_data) {
- return (event_data.what === "modified" &&
- event_data.edited_fields.indexOf("preview_diff") >= 0);
-};
-
-}, '0.1', {requires: ['node', 'lp.client', 'lp.anim',
- 'lp.code.branchmergeproposal.reviewcomment']});
=== removed file 'lib/lp/code/javascript/tests/test_branchmergeproposal.updater.html'
--- lib/lp/code/javascript/tests/test_branchmergeproposal.updater.html 2012-10-26 09:54:28 +0000
+++ lib/lp/code/javascript/tests/test_branchmergeproposal.updater.html 1970-01-01 00:00:00 +0000
@@ -1,98 +0,0 @@
-<!DOCTYPE html>
-<!--
-Copyright 2012 Canonical Ltd. This software is licensed under the
-GNU Affero General Public License version 3 (see the file LICENSE).
--->
-
-<html>
- <head>
- <title>Test branchmergeproposal</title>
-
- <!-- YUI and test setup -->
- <script type="text/javascript"
- src="../../../../../build/js/yui/yui/yui.js">
- </script>
- <link rel="stylesheet"
- href="../../../../../build/js/yui/console/assets/console-core.css" />
- <link rel="stylesheet"
- href="../../../../../build/js/yui/test-console/assets/skins/sam/test-console.css" />
- <link rel="stylesheet"
- href="../../../../../build/js/yui/test/assets/skins/sam/test.css" />
-
- <script type="text/javascript"
- src="../../../../../build/js/lp/app/testing/testrunner.js"></script>
-
- <link rel="stylesheet" href="../../../app/javascript/testing/test.css" />
-
- <!-- Dependencies -->
- <script type="text/javascript"
- src="../../../../../build/js/lp/..."></script>
- <script type="text/javascript"
- src="../../../../../build/js/lp/app/client.js"></script>
- <script type="text/javascript"
- src="../../../../../build/js/lp/app/lp.js"></script>
- <script type="text/javascript"
- src="../../../../../build/js/lp/app/anim/anim.js"></script>
- <script type="text/javascript"
- src="../../../../../build/js/lp/app/extras/extras.js"></script>
- <script type="text/javascript"
- src="../../../../../build/js/lp/app/testing/mockio.js"></script>
- <script type="text/javascript"
- src="../../../../../build/js/lp/code/branchmergeproposal.reviewcomment.js"></script>
-
- <!-- The module under test. -->
- <script type="text/javascript" src="../branchmergeproposal.updater.js"></script>
-
- <!-- Any css assert for this module. -->
- <!-- <link rel="stylesheet" href="../assets/branchmergeproposal-core.css" /> -->
-
- <!-- The test suite. -->
- <script type="text/javascript" src="test_branchmergeproposal.updater.js"></script>
-
- <!-- expected variable -->
- <script type="text/javascript">
- var LP = {
- cache: {},
- links: {}
- };
- </script>
-
- </head>
- <body class="yui3-skin-sam">
- <ul id="suites">
- <!-- <li>lp.large_indicator.test</li> -->
- <li>lp.branchmergeproposal.updater.test</li>
- </ul>
- <div id="placeholder" style="display:none;">
- </div>
-
- <script type="text/x-template" id="pending-mp">
- <table id="proposal-summary">
- <tr id="summary-row-9-target-branch">
- <th>Merge into:</th>
- <td>
- <a href="/~me/project/branch"
- class="sprite branch">lp://dev/~me/project/branch</a>
- </td>
- </tr>
- </table>
- <div id="diff-area">
- <div class="pending-update" id="diff-pending-update">
- <h3>Updating diff...</h3>
- <p>An updated diff will be available in a few minutes.</p>
- </div>
- </div>
- </script>
-
- <script type="text/x-template" id="current-mp">
- <div id="diff-area">
- <div id="review-diff">
- <h2>Preview Diff</h2>
- <div class="diff-content">Example diff</div>
- </div>
- </div>
- </script>
-
-
- </body>
-</html>
=== removed file 'lib/lp/code/javascript/tests/test_branchmergeproposal.updater.js'
--- lib/lp/code/javascript/tests/test_branchmergeproposal.updater.js 2014-03-31 19:40:35 +0000
+++ lib/lp/code/javascript/tests/test_branchmergeproposal.updater.js 1970-01-01 00:00:00 +0000
@@ -1,162 +0,0 @@
-/* Copyright 2011 Canonical Ltd. This software is licensed under the
- * GNU Affero General Public License version 3 (see the file LICENSE).
- *
- * Tests for lp.code.branchmergeproposal.updater.
- *
- */
-YUI.add('lp.branchmergeproposal.updater.test', function (Y) {
-var module = Y.lp.code.branchmergeproposal.updater;
-var UpdaterWidget = module.UpdaterWidget;
-
-
-var tests = Y.namespace('lp.branchmergeproposal.updater.test');
-tests.suite = new Y.Test.Suite("BranchMergeProposal Updater Tests");
-
-/*
- * Tests for when the updater is built on top of a pending diff.
- *
- */
-
-var pending_mp = Y.one('#pending-mp').getContent();
-
-tests.suite.add(new Y.Test.Case({
-
- name: 'branchmergeproposal-updater-pending-tests',
-
- setUp: function() {
- Y.one("#placeholder")
- .empty()
- .append(Y.Node.create(pending_mp));
- var diff_area = Y.one('#diff-area');
- var summary_node = Y.one('#proposal-summary');
- this.updater = new UpdaterWidget(
- {srcNode: diff_area, summary_node: summary_node});
-
- LP.cache.context = {
- web_link: "https://code.launchpad.dev/~foo/bar/foobr/+merge/123"};
-
- },
-
- tearDown: function() {
- this.updater.destroy();
- },
-
- test_default_values: function() {
- Y.Assert.isTrue(this.updater.get('pending'));
- Y.Assert.isNull(this.updater.get('diff_stats'));
- },
-
- test__setup_diff_container: function() {
- this.updater._setup_diff_container();
- Y.Assert.isFalse(this.updater.get('pending'));
- Y.Assert.areEqual(
- "Preview Diff ",
- this.updater.get(
- 'srcNode').one('#review-diff h2').get('text'));
- Y.Assert.areEqual(
- "",
- this.updater.get(
- 'srcNode').one('.diff-content').get('text'));
- },
-
- test__setup_diff_stats_container: function() {
- Y.Assert.isNull(this.updater.get('diff_stats'));
- this.updater._setup_diff_stats_container();
- Y.Assert.areEqual('', this.updater.get('diff_stats'));
- },
-
- test_set_diff_stats: function() {
- this.updater.set('diff_stats', '13 lines (+4/-0) 1 file modified');
- Y.Assert.areEqual(
- '13 lines (+4/-0) 1 file modified',
- this.updater.get('diff_stats'));
- },
-
- test_set_status_updating: function() {
- this.updater.set_status_updating();
- Y.Assert.areEqual(
- '/@@/spinner',
- Y.one('h2').one('img').getAttribute('src'));
- },
-
- test_set_status_longpolling: function() {
- this.updater.set_status_longpolling();
- Y.Assert.areEqual(
- '/@@/longpoll_loading',
- Y.one('h2').one('img').getAttribute('src'));
- },
-
- test_set_status_longpollerror: function() {
- this.updater.set_status_longpollerror();
- Y.Assert.areEqual(
- '/@@/longpoll_error',
- Y.one('h2').one('img').getAttribute('src'));
- },
-
- test_cleanup_status: function() {
- this.updater._setup_diff_container();
- this.updater.set_status_updating();
- this.updater.cleanup_status();
- Y.Assert.areEqual(
- 'Preview Diff ',
- Y.one('h2').get('innerHTML'));
- },
-
- test_update_stats_success: function() {
- var mockio = new Y.lp.testing.mockio.MockIo();
- this.updater.get('lp_client').io_provider = mockio;
- Y.Assert.isNull(this.updater.get('diff_stats'));
- this.updater.update_stats();
- mockio.success({
- responseText: '13 lines (+4/-0) 1 file modified',
- responseHeaders: {'Content-Type': 'text/html'}});
-
- Y.Assert.areEqual(
- '13 lines (+4/-0) 1 file modified',
- this.updater.get('diff_stats'));
- },
-
- test_update_fires_event: function() {
- var fired = false;
- var mockio = new Y.lp.testing.mockio.MockIo();
- this.updater.get('lp_client').io_provider = mockio;
- this.updater.on(this.updater.NAME + '.updated', function() {
- fired = true;
- });
- this.updater.update();
- mockio.success({
- responseText: '13 lines (+4/-0) 1 file modified',
- responseHeaders: {'Content-Type': 'text/html'}});
- Y.Assert.isTrue(fired);
- }
-
-}));
-
-
-tests.suite.add(new Y.Test.Case({
-
- name: 'branchmergeproposal-updater-utilities',
-
- test_is_mp_diff_updated_modified: function() {
- var data = {what: 'modified', edited_fields: ['preview_diff']};
- Y.Assert.isTrue(module.is_mp_diff_updated(data));
- },
-
- test_is_mp_diff_updater_deleted: function() {
- var data = {what: 'deleted'};
- Y.Assert.isFalse(module.is_mp_diff_updated(data));
- },
-
- test_is_mp_diff_updated_title_changed: function() {
- var data = {what: 'modified', edited_fields: ['title']};
- Y.Assert.isFalse(module.is_mp_diff_updated(data));
- }
-
-}));
-
-
-}, '0.1', {
- requires: ['lp.testing.runner', 'test', 'dump', 'test-console', 'node',
- 'lp.testing.mockio', 'event',
- 'lp.code.branchmergeproposal.updater']
-});
=== modified file 'lib/lp/code/templates/branchmergeproposal-index.pt'
--- lib/lp/code/templates/branchmergeproposal-index.pt 2019-01-31 13:48:34 +0000
+++ lib/lp/code/templates/branchmergeproposal-index.pt 2019-04-16 14:35:10 +0000
@@ -185,13 +185,10 @@
<div class="yui-g" tal:condition="python: not view.show_diff_update_link and view.pending_diff">
<div class="pending-update" id="diff-pending-update">
<h3>Updating diff...</h3>
- <p tal:condition="not: features/longpoll.merge_proposals.enabled">
+ <p>
An updated diff will be available in a few minutes. Reload to see the
changes.
</p>
- <p tal:condition="features/longpoll.merge_proposals.enabled">
- An updated diff is being calculated and will appear automatically when ready.
- </p>
</div>
</div>
<div class="yui-g" tal:condition="view/show_diff_update_link">
@@ -226,7 +223,7 @@
conf = <tal:status-config replace="view/status_config" />
LPJS.use('io-base', 'lp.code.branchmergeproposal.reviewcomment',
'lp.code.branchmergeproposal.status', 'lp.app.comment',
- 'lp.code.branchmergeproposal.updater', 'lp.app.widgets.expander',
+ 'lp.app.widgets.expander',
'lp.code.branch.revisionexpander',
'lp.code.branchmergeproposal.inlinecomments', function(Y) {
@@ -252,23 +249,6 @@
diffnav.render();
}
- if (Y.Lang.isValue(LP.cache.merge_proposal_event_key)) {
- var upt = Y.lp.code.branchmergeproposal.updater;
- var cfg = {
- srcNode: Y.one('#diff-area'),
- summary_node: Y.one('#proposal-summary')
- };
- var updater = new upt.UpdaterWidget(cfg);
- Y.on(LP.cache.merge_proposal_event_key, function(data) {
- if (upt.is_mp_diff_updated(data)) {
- updater.update();
- }
- });
- updater.on(updater.NAME + '.updated', function() {
- diffnav.render();
- });
- }
-
LP.cache.comment_context = LP.cache.context;
var cl = new Y.lp.app.comment.CommentList({
comment_list_container: Y.one('#conversation')
=== modified file 'lib/lp/scripts/runlaunchpad.py'
--- lib/lp/scripts/runlaunchpad.py 2018-05-21 20:30:16 +0000
+++ lib/lp/scripts/runlaunchpad.py 2019-04-16 14:35:10 +0000
@@ -1,4 +1,4 @@
-# Copyright 2009-2018 Canonical Ltd. This software is licensed under the
+# Copyright 2009-2019 Canonical Ltd. This software is licensed under the
# GNU Affero General Public License version 3 (see the file LICENSE).
__metaclass__ = type
@@ -27,7 +27,6 @@
)
from lp.services.rabbit.server import RabbitServer
from lp.services.sitesearch import bingtestservice
-from lp.services.txlongpoll.server import TxLongPollServer
def make_abspath(path):
@@ -237,28 +236,6 @@
self.useFixture(self.server)
-class TxLongPollService(Service):
- """A TxLongPoll service."""
-
- @property
- def should_launch(self):
- return config.txlongpoll.launch
-
- def launch(self):
- twistd_bin = os.path.join(config.root, 'bin', 'twistd')
- broker_hostname, broker_port = as_host_port(
- config.rabbitmq.host, None, None)
- self.server = TxLongPollServer(
- twistd_bin=twistd_bin,
- frontend_port=config.txlongpoll.frontend_port,
- broker_user=config.rabbitmq.userid,
- broker_password=config.rabbitmq.password,
- broker_vhost=config.rabbitmq.virtual_host,
- broker_host=broker_hostname,
- broker_port=broker_port)
- self.useFixture(self.server)
-
-
def stop_process(process):
"""kill process and BLOCK until process dies.
@@ -284,7 +261,6 @@
'codebrowse': CodebrowseService(),
'memcached': MemcachedService(),
'rabbitmq': RabbitService(),
- 'txlongpoll': TxLongPollService(),
}
=== modified file 'lib/lp/scripts/tests/test_runlaunchpad.py'
--- lib/lp/scripts/tests/test_runlaunchpad.py 2018-05-21 20:30:16 +0000
+++ lib/lp/scripts/tests/test_runlaunchpad.py 2019-04-16 14:35:10 +0000
@@ -1,4 +1,4 @@
-# Copyright 2009-2018 Canonical Ltd. This software is licensed under the
+# Copyright 2009-2019 Canonical Ltd. This software is licensed under the
# GNU Affero General Public License version 3 (see the file LICENSE).
"""Tests for runlaunchpad.py"""
@@ -156,10 +156,6 @@
if config.rabbitmq.launch:
expected.append(SERVICES['rabbitmq'])
- # TxLongPoll may or may not be asked to run.
- if config.txlongpoll.launch:
- expected.append(SERVICES['txlongpoll'])
-
expected = sorted(expected)
self.assertEqual(expected, services)
=== modified file 'lib/lp/services/config/schema-lazr.conf'
--- lib/lp/services/config/schema-lazr.conf 2019-03-26 20:51:38 +0000
+++ lib/lp/services/config/schema-lazr.conf 2019-04-16 14:35:10 +0000
@@ -1601,16 +1601,6 @@
# datatype: string
virtual_host: none
-[txlongpoll]
-# Should TxLongPoll be launched by default?
-# datatype: boolean
-launch: False
-# The port at which TxLongPoll is listening.
-# datatype: string
-frontend_port: none
-# The uri that should be a proxy to the TxLongPoll server.
-uri: /+longpoll/
-
[request_daily_builds]
dbuser: request-daily-builds
=== modified file 'lib/lp/services/configure.zcml'
--- lib/lp/services/configure.zcml 2018-03-16 14:50:01 +0000
+++ lib/lp/services/configure.zcml 2019-04-16 14:35:10 +0000
@@ -1,4 +1,4 @@
-<!-- Copyright 2010-2011 Canonical Ltd. This software is licensed under the
+<!-- Copyright 2010-2019 Canonical Ltd. This software is licensed under the
GNU Affero General Public License version 3 (see the file LICENSE).
-->
@@ -16,7 +16,6 @@
<include package=".inlinehelp" file="meta.zcml" />
<include package=".job" />
<include package=".librarian" />
- <include package=".longpoll" />
<include package=".mail" />
<include package=".memcache" />
<include package=".messages" />
=== modified file 'lib/lp/services/features/flags.py'
--- lib/lp/services/features/flags.py 2018-05-21 20:30:16 +0000
+++ lib/lp/services/features/flags.py 2019-04-16 14:35:10 +0000
@@ -1,4 +1,4 @@
-# Copyright 2010-2018 Canonical Ltd. This software is licensed under the
+# Copyright 2010-2019 Canonical Ltd. This software is licensed under the
# GNU Affero General Public License version 3 (see the file LICENSE).
__all__ = [
@@ -171,13 +171,6 @@
'None are enabled',
'',
''),
- ('longpoll.merge_proposals.enabled',
- 'boolean',
- ('Enables the longpoll mechanism for merge proposals so that diffs, '
- 'for example, are updated in-page when they are ready.'),
- '',
- '',
- ''),
('ajax.batch_navigator.enabled',
'boolean',
('If true, batch navigators which have been wired to do so use ajax '
=== removed directory 'lib/lp/services/longpoll'
=== removed file 'lib/lp/services/longpoll/__init__.py'
=== removed directory 'lib/lp/services/longpoll/adapters'
=== removed file 'lib/lp/services/longpoll/adapters/__init__.py'
=== removed file 'lib/lp/services/longpoll/adapters/event.py'
--- lib/lp/services/longpoll/adapters/event.py 2015-07-09 12:18:51 +0000
+++ lib/lp/services/longpoll/adapters/event.py 1970-01-01 00:00:00 +0000
@@ -1,71 +0,0 @@
-# Copyright 2011 Canonical Ltd. This software is licensed under the
-# GNU Affero General Public License version 3 (see the file LICENSE).
-
-"""Long poll adapters."""
-
-__metaclass__ = type
-__all__ = [
- "generate_event_key",
- "LongPollEvent",
- ]
-
-from zope.component import getUtility
-
-from lp.services.messaging.interfaces import IMessageSession
-
-
-def router_factory(event_key):
- """Get a router for the given `event_key`."""
- return getUtility(IMessageSession).getProducer(event_key)
-
-
-def generate_event_key(*components):
- """Generate a suitable event name."""
- if len(components) == 0:
- raise AssertionError(
- "Event keys must contain at least one component.")
- return "longpoll.event.%s" % ".".join(
- str(component) for component in components)
-
-
-class LongPollEvent:
- """Base-class for event adapters.
-
- Sub-classes need to define the `event_key` property and declare something
- along the lines of::
-
- @adapter(IAwesomeThing)
- @implementer(ILongPollEvent)
- class LongPollAwesomeThingEvent(LongPollEvent):
- ...
-
- Alternatively, use the `long_poll_event` class decorator::
-
- @long_poll_event(IAwesomeThing)
- class LongPollAwesomeThingEvent(LongPollEvent):
- ...
-
- In both cases the adapter should be registered in a `configure.zcml`
- somewhere sensible::
-
- <adapter factory=".adapters.LongPollAwesomeThingEvent" />
-
- """
-
- def __init__(self, source):
- self.source = source
-
- @property
- def event_key(self):
- """See `ILongPollEvent`."""
- raise NotImplementedError(self.__class__.event_key)
-
- def emit(self, **data):
- """See `ILongPollEvent`.
-
- The data will be updated with `event_key`, a copy of `self.event_key`.
- """
- event_key = self.event_key
- data.update(event_key=event_key)
- router = router_factory(event_key)
- router.send(data)
=== removed file 'lib/lp/services/longpoll/adapters/storm.py'
--- lib/lp/services/longpoll/adapters/storm.py 2011-10-05 15:46:30 +0000
+++ lib/lp/services/longpoll/adapters/storm.py 1970-01-01 00:00:00 +0000
@@ -1,116 +0,0 @@
-# Copyright 2011 Canonical Ltd. This software is licensed under the
-# GNU Affero General Public License version 3 (see the file LICENSE).
-
-"""Long-poll life-cycle adapters."""
-
-from __future__ import absolute_import
-
-__metaclass__ = type
-__all__ = []
-
-from lazr.lifecycle.interfaces import (
- IObjectCreatedEvent,
- IObjectDeletedEvent,
- IObjectModifiedEvent,
- )
-from storm.base import Storm
-from storm.info import (
- get_cls_info,
- get_obj_info,
- )
-from zope.component import adapter
-from zope.interface.interfaces import IAttribute
-from zope.security.proxy import removeSecurityProxy
-
-from lp.services.longpoll.adapters.event import (
- generate_event_key,
- LongPollEvent,
- )
-from lp.services.longpoll.interfaces import (
- ILongPollEvent,
- long_poll_event,
- )
-
-
-def gen_primary_key(model_instance):
- """Generate the primary key values for the given model instance."""
- cls_info = get_obj_info(model_instance).cls_info
- for primary_key_column in cls_info.primary_key:
- yield primary_key_column.__get__(model_instance)
-
-
-def get_primary_key(model_instance):
- """Return the primary key for the given model instance.
-
- If the primary key contains only one value it is returned, otherwise all
- the primary key values are returned in a tuple.
- """
- pkey = tuple(gen_primary_key(model_instance))
- return pkey[0] if len(pkey) == 1 else pkey
-
-
-@long_poll_event(Storm)
-class LongPollStormEvent(LongPollEvent):
- """A `ILongPollEvent` for events of `Storm` objects.
-
- This class knows how to construct a stable event key given a Storm object.
- """
-
- @property
- def event_key(self):
- """See `ILongPollEvent`.
-
- Constructs the key from the table name and primary key values of the
- Storm model object.
- """
- cls_info = get_obj_info(self.source).cls_info
- return generate_event_key(
- cls_info.table.name.lower(),
- *gen_primary_key(self.source))
-
-
-@long_poll_event(type(Storm))
-class LongPollStormCreationEvent(LongPollEvent):
- """A `ILongPollEvent` for events of `Storm` *classes*.
-
- This class knows how to construct a stable event key given a Storm class.
- """
-
- @property
- def event_key(self):
- """See `ILongPollEvent`.
-
- Constructs the key from the table name of the Storm class.
- """
- cls_info = get_cls_info(self.source)
- return generate_event_key(
- cls_info.table.name.lower())
-
-
-@adapter(Storm, IObjectCreatedEvent)
-def object_created(model_instance, object_event):
- """Subscription handler for `Storm` creation events."""
- model_class = removeSecurityProxy(model_instance).__class__
- event = ILongPollEvent(model_class)
- event.emit(what="created", id=get_primary_key(model_instance))
-
-
-@adapter(Storm, IObjectDeletedEvent)
-def object_deleted(model_instance, object_event):
- """Subscription handler for `Storm` deletion events."""
- event = ILongPollEvent(model_instance)
- event.emit(what="deleted", id=get_primary_key(model_instance))
-
-
-@adapter(Storm, IObjectModifiedEvent)
-def object_modified(model_instance, object_event):
- """Subscription handler for `Storm` modification events."""
- edited_fields = object_event.edited_fields
- if edited_fields is not None and len(edited_fields) != 0:
- edited_field_names = sorted(
- (field.__name__ if IAttribute.providedBy(field) else field)
- for field in edited_fields)
- event = ILongPollEvent(model_instance)
- event.emit(
- what="modified", edited_fields=edited_field_names,
- id=get_primary_key(model_instance))
=== removed file 'lib/lp/services/longpoll/adapters/subscriber.py'
--- lib/lp/services/longpoll/adapters/subscriber.py 2015-07-09 12:18:51 +0000
+++ lib/lp/services/longpoll/adapters/subscriber.py 1970-01-01 00:00:00 +0000
@@ -1,58 +0,0 @@
-# Copyright 2011 Canonical Ltd. This software is licensed under the
-# GNU Affero General Public License version 3 (see the file LICENSE).
-
-"""Long poll adapters."""
-
-__metaclass__ = type
-__all__ = [
- "generate_subscribe_key",
- "LongPollApplicationRequestSubscriber",
- ]
-
-from uuid import uuid4
-
-from lazr.restful.interfaces import IJSONRequestCache
-from zope.component import (
- adapter,
- getUtility,
- )
-from zope.interface import implementer
-from zope.publisher.interfaces import IApplicationRequest
-
-from lp.services.config import config
-from lp.services.longpoll.interfaces import ILongPollSubscriber
-from lp.services.messaging.interfaces import IMessageSession
-
-
-def generate_subscribe_key():
- """Generate a suitable new, unique, subscribe key."""
- return "longpoll.subscribe.%s" % uuid4()
-
-
-@adapter(IApplicationRequest)
-@implementer(ILongPollSubscriber)
-class LongPollApplicationRequestSubscriber:
-
- def __init__(self, request):
- self.request = request
-
- @property
- def subscribe_key(self):
- objects = IJSONRequestCache(self.request).objects
- if "longpoll" in objects:
- return objects["longpoll"]["key"]
- return None
-
- def subscribe(self, event):
- cache = IJSONRequestCache(self.request)
- if "longpoll" not in cache.objects:
- cache.objects["longpoll"] = {
- "uri": config.txlongpoll.uri,
- "key": generate_subscribe_key(),
- "subscriptions": [],
- }
- session = getUtility(IMessageSession)
- subscribe_queue = session.getConsumer(self.subscribe_key)
- producer = session.getProducer(event.event_key)
- producer.associateConsumer(subscribe_queue)
- cache.objects["longpoll"]["subscriptions"].append(event.event_key)
=== removed directory 'lib/lp/services/longpoll/adapters/tests'
=== removed file 'lib/lp/services/longpoll/adapters/tests/__init__.py'
=== removed file 'lib/lp/services/longpoll/adapters/tests/test_event.py'
--- lib/lp/services/longpoll/adapters/tests/test_event.py 2015-07-08 16:05:11 +0000
+++ lib/lp/services/longpoll/adapters/tests/test_event.py 1970-01-01 00:00:00 +0000
@@ -1,78 +0,0 @@
-# Copyright 2011 Canonical Ltd. This software is licensed under the
-# GNU Affero General Public License version 3 (see the file LICENSE).
-
-"""Long-poll event adapter tests."""
-
-__metaclass__ = type
-
-from zope.interface import implementer
-
-from lp.services.longpoll.adapters.event import (
- generate_event_key,
- LongPollEvent,
- )
-from lp.services.longpoll.interfaces import ILongPollEvent
-from lp.services.longpoll.testing import (
- capture_longpoll_emissions,
- LongPollEventRecord,
- )
-from lp.testing import TestCase
-from lp.testing.layers import LaunchpadFunctionalLayer
-from lp.testing.matchers import Contains
-
-
-@implementer(ILongPollEvent)
-class FakeEvent(LongPollEvent):
-
- @property
- def event_key(self):
- return "event-key-%s" % self.source
-
-
-class TestLongPollEvent(TestCase):
-
- layer = LaunchpadFunctionalLayer
-
- def test_interface(self):
- event = FakeEvent("source")
- self.assertProvides(event, ILongPollEvent)
-
- def test_event_key(self):
- # event_key is not implemented in LongPollEvent; subclasses must
- # provide it.
- event = LongPollEvent("source")
- self.assertRaises(NotImplementedError, getattr, event, "event_key")
-
- def test_emit(self):
- # LongPollEvent.emit() sends the given data to `event_key`.
- event = FakeEvent("source")
- event_data = {"hello": 1234}
- with capture_longpoll_emissions() as log:
- event.emit(**event_data)
- expected_message = LongPollEventRecord(
- event_key=event.event_key,
- data=dict(event_data, event_key=event.event_key))
- self.assertThat(log, Contains(expected_message))
-
-
-class TestFunctions(TestCase):
-
- def test_generate_event_key_no_components(self):
- self.assertRaises(
- AssertionError, generate_event_key)
-
- def test_generate_event_key(self):
- self.assertEqual(
- "longpoll.event.event-name",
- generate_event_key("event-name"))
- self.assertEqual(
- "longpoll.event.source-name.event-name",
- generate_event_key("source-name", "event-name"))
- self.assertEqual(
- "longpoll.event.type-name.source-name.event-name",
- generate_event_key("type-name", "source-name", "event-name"))
-
- def test_generate_event_key_stringifies_components(self):
- self.assertEqual(
- "longpoll.event.job.1234.COMPLETED",
- generate_event_key("job", 1234, "COMPLETED"))
=== removed file 'lib/lp/services/longpoll/adapters/tests/test_storm.py'
--- lib/lp/services/longpoll/adapters/tests/test_storm.py 2012-01-01 02:58:52 +0000
+++ lib/lp/services/longpoll/adapters/tests/test_storm.py 1970-01-01 00:00:00 +0000
@@ -1,170 +0,0 @@
-# Copyright 2011 Canonical Ltd. This software is licensed under the
-# GNU Affero General Public License version 3 (see the file LICENSE).
-
-"""Long-poll event adapter tests."""
-
-__metaclass__ = type
-
-from lazr.lifecycle.event import (
- ObjectCreatedEvent,
- ObjectDeletedEvent,
- ObjectModifiedEvent,
- )
-from storm.base import Storm
-from storm.properties import Int
-from zope.event import notify
-from zope.interface import Attribute
-
-from lp.services.longpoll.adapters.storm import (
- gen_primary_key,
- get_primary_key,
- )
-from lp.services.longpoll.interfaces import ILongPollEvent
-from lp.services.longpoll.testing import (
- capture_longpoll_emissions,
- LongPollEventRecord,
- )
-from lp.testing import TestCase
-from lp.testing.layers import LaunchpadFunctionalLayer
-from lp.testing.matchers import Provides
-
-
-class FakeStormClass(Storm):
-
- __storm_table__ = 'FakeTable'
-
- id = Int(primary=True)
-
-
-class FakeStormCompoundPrimaryKeyClass(Storm):
-
- __storm_table__ = 'FakeTableWithCompoundPrimaryKey'
- __storm_primary__ = 'id1', 'id2'
-
- id1 = Int()
- id2 = Int()
-
-
-class TestFunctions(TestCase):
-
- def test_gen_primary_key(self):
- # gen_primary_key() returns an iterable of values from the model
- # instance's primary key.
- storm_object = FakeStormClass()
- storm_object.id = 1234
- self.assertEqual([1234], list(gen_primary_key(storm_object)))
-
- def test_gen_primary_key_compound_key(self):
- # gen_primary_key() returns an iterable of values from the model
- # instance's primary key.
- storm_object = FakeStormCompoundPrimaryKeyClass()
- storm_object.id1 = 1234
- storm_object.id2 = 5678
- self.assertEqual([1234, 5678], list(gen_primary_key(storm_object)))
-
- def test_get_primary_key(self):
- # get_primary_key() returns the value of the model instance's primary
- # key.
- storm_object = FakeStormClass()
- storm_object.id = 1234
- self.assertEqual(1234, get_primary_key(storm_object))
-
- def test_get_primary_key_compound_key(self):
- # get_primary_key() returns a tuple of all the values in the model
- # instance's primary key when the model uses a compound primary key.
- storm_object = FakeStormCompoundPrimaryKeyClass()
- storm_object.id1 = 1234
- storm_object.id2 = 5678
- self.assertEqual((1234, 5678), get_primary_key(storm_object))
-
-
-class TestStormLifecycle(TestCase):
-
- layer = LaunchpadFunctionalLayer
-
- def test_storm_event_adapter(self):
- storm_object = FakeStormClass()
- storm_object.id = 1234
- event = ILongPollEvent(storm_object)
- self.assertThat(event, Provides(ILongPollEvent))
- self.assertEqual(
- "longpoll.event.faketable.1234",
- event.event_key)
-
- def test_storm_creation_event_adapter(self):
- event = ILongPollEvent(FakeStormClass)
- self.assertThat(event, Provides(ILongPollEvent))
- self.assertEqual(
- "longpoll.event.faketable",
- event.event_key)
-
- def test_storm_object_created(self):
- storm_object = FakeStormClass()
- storm_object.id = 1234
- with capture_longpoll_emissions() as log:
- notify(ObjectCreatedEvent(storm_object))
- expected = LongPollEventRecord(
- "longpoll.event.faketable", {
- "event_key": "longpoll.event.faketable",
- "what": "created",
- "id": 1234,
- })
- self.assertEqual([expected], log)
-
- def test_storm_object_deleted(self):
- storm_object = FakeStormClass()
- storm_object.id = 1234
- with capture_longpoll_emissions() as log:
- notify(ObjectDeletedEvent(storm_object))
- expected = LongPollEventRecord(
- "longpoll.event.faketable.1234", {
- "event_key": "longpoll.event.faketable.1234",
- "what": "deleted",
- "id": 1234,
- })
- self.assertEqual([expected], log)
-
- def test_storm_object_modified(self):
- storm_object = FakeStormClass()
- storm_object.id = 1234
- with capture_longpoll_emissions() as log:
- object_event = ObjectModifiedEvent(
- storm_object, storm_object, ("itchy", "scratchy"))
- notify(object_event)
- expected = LongPollEventRecord(
- "longpoll.event.faketable.1234", {
- "event_key": "longpoll.event.faketable.1234",
- "what": "modified",
- "edited_fields": ["itchy", "scratchy"],
- "id": 1234,
- })
- self.assertEqual([expected], log)
-
- def test_storm_object_modified_no_edited_fields(self):
- # A longpoll event is not emitted unless edited_fields is populated.
- storm_object = FakeStormClass()
- storm_object.id = 1234
- with capture_longpoll_emissions() as log:
- notify(ObjectModifiedEvent(storm_object, storm_object, None))
- self.assertEqual([], log)
- with capture_longpoll_emissions() as log:
- notify(ObjectModifiedEvent(storm_object, storm_object, ()))
- self.assertEqual([], log)
-
- def test_storm_object_modified_edited_fields_are_zope_attributes(self):
- # The names of IAttribute fields in edited_fields are used in the
- # longpoll event.
- storm_object = FakeStormClass()
- storm_object.id = 1234
- with capture_longpoll_emissions() as log:
- object_event = ObjectModifiedEvent(
- storm_object, storm_object, ("foo", Attribute("bar")))
- notify(object_event)
- expected = LongPollEventRecord(
- "longpoll.event.faketable.1234", {
- "event_key": "longpoll.event.faketable.1234",
- "what": "modified",
- "edited_fields": ["bar", "foo"],
- "id": 1234,
- })
- self.assertEqual([expected], log)
=== removed file 'lib/lp/services/longpoll/adapters/tests/test_subscriber.py'
--- lib/lp/services/longpoll/adapters/tests/test_subscriber.py 2015-07-08 16:05:11 +0000
+++ lib/lp/services/longpoll/adapters/tests/test_subscriber.py 1970-01-01 00:00:00 +0000
@@ -1,137 +0,0 @@
-# Copyright 2011 Canonical Ltd. This software is licensed under the
-# GNU Affero General Public License version 3 (see the file LICENSE).
-
-"""Long-poll subscriber adapter tests."""
-
-__metaclass__ = type
-
-from itertools import count
-
-from lazr.restful.interfaces import IJSONRequestCache
-from testtools.matchers import (
- Not,
- StartsWith,
- )
-from zope.component import getUtility
-from zope.interface import implementer
-
-from lp.services.longpoll.adapters.subscriber import (
- generate_subscribe_key,
- LongPollApplicationRequestSubscriber,
- )
-from lp.services.longpoll.interfaces import (
- ILongPollEvent,
- ILongPollSubscriber,
- )
-from lp.services.messaging.interfaces import IMessageSession
-from lp.services.webapp.servers import LaunchpadTestRequest
-from lp.testing import TestCase
-from lp.testing.layers import LaunchpadFunctionalLayer
-from lp.testing.matchers import Contains
-
-
-@implementer(ILongPollEvent)
-class FakeEvent:
-
- event_key_indexes = count(1)
-
- def __init__(self):
- self.event_key = "event-key-%d" % next(self.event_key_indexes)
-
-
-class TestLongPollSubscriber(TestCase):
-
- layer = LaunchpadFunctionalLayer
-
- def test_interface(self):
- request = LaunchpadTestRequest()
- subscriber = LongPollApplicationRequestSubscriber(request)
- self.assertProvides(subscriber, ILongPollSubscriber)
-
- def test_subscribe_key(self):
- request = LaunchpadTestRequest()
- subscriber = LongPollApplicationRequestSubscriber(request)
- # A subscribe key is not generated yet.
- self.assertIs(subscriber.subscribe_key, None)
- # It it only generated on the first subscription.
- subscriber.subscribe(FakeEvent())
- subscribe_key = subscriber.subscribe_key
- self.assertIsInstance(subscribe_key, str)
- self.assertNotEqual(0, len(subscribe_key))
- # It remains the same for later subscriptions.
- subscriber.subscribe(FakeEvent())
- self.assertEqual(subscribe_key, subscriber.subscribe_key)
-
- def test_adapter(self):
- request = LaunchpadTestRequest()
- subscriber = ILongPollSubscriber(request)
- self.assertIsInstance(
- subscriber, LongPollApplicationRequestSubscriber)
- # A difference subscriber is returned on subsequent adaptions, but it
- # has the same subscribe_key.
- subscriber2 = ILongPollSubscriber(request)
- self.assertIsNot(subscriber, subscriber2)
- self.assertEqual(subscriber.subscribe_key, subscriber2.subscribe_key)
-
- def test_subscribe_queue(self):
- # LongPollApplicationRequestSubscriber.subscribe() creates a new queue
- # with a new unique name that is bound to the event's event_key.
- request = LaunchpadTestRequest()
- event = FakeEvent()
- subscriber = ILongPollSubscriber(request)
- subscriber.subscribe(event)
- message = '{"hello": 1234}'
- session = getUtility(IMessageSession)
- routing_key = session.getProducer(event.event_key)
- routing_key.send(message)
- session.flush()
- subscribe_queue = session.getConsumer(subscriber.subscribe_key)
- self.assertEqual(
- message, subscribe_queue.receive(timeout=5))
-
- def test_json_cache_not_populated_on_init(self):
- # LongPollApplicationRequestSubscriber does not put the name of the
- # new queue into the JSON cache.
- request = LaunchpadTestRequest()
- cache = IJSONRequestCache(request)
- self.assertThat(cache.objects, Not(Contains("longpoll")))
- ILongPollSubscriber(request)
- self.assertThat(cache.objects, Not(Contains("longpoll")))
-
- def test_longpoll_uri_config(self):
- # The JSON cache contains config.txlongpoll.uri.
- self.pushConfig("txlongpoll", uri="/+longpoll/")
- request = LaunchpadTestRequest()
- cache = IJSONRequestCache(request)
- ILongPollSubscriber(request).subscribe(FakeEvent())
- self.assertEqual('/+longpoll/', cache.objects["longpoll"]["uri"])
-
- def test_json_cache_populated_on_subscribe(self):
- # To aid with debugging the event_key of subscriptions are added to
- # the JSON cache.
- request = LaunchpadTestRequest()
- cache = IJSONRequestCache(request)
- event1 = FakeEvent()
- ILongPollSubscriber(request).subscribe(event1) # Side-effects!
- self.assertThat(cache.objects, Contains("longpoll"))
- self.assertThat(cache.objects["longpoll"], Contains("key"))
- self.assertThat(cache.objects["longpoll"], Contains("subscriptions"))
- self.assertEqual(
- [event1.event_key],
- cache.objects["longpoll"]["subscriptions"])
- # More events can be subscribed.
- event2 = FakeEvent()
- ILongPollSubscriber(request).subscribe(event2)
- self.assertEqual(
- [event1.event_key, event2.event_key],
- cache.objects["longpoll"]["subscriptions"])
-
-
-class TestFunctions(TestCase):
-
- def test_generate_subscribe_key(self):
- subscribe_key = generate_subscribe_key()
- expected_prefix = "longpoll.subscribe."
- self.assertThat(subscribe_key, StartsWith(expected_prefix))
- # The key contains a 36 character UUID.
- self.assertEqual(len(expected_prefix) + 36, len(subscribe_key))
=== removed file 'lib/lp/services/longpoll/configure.zcml'
--- lib/lp/services/longpoll/configure.zcml 2011-10-05 15:14:53 +0000
+++ lib/lp/services/longpoll/configure.zcml 1970-01-01 00:00:00 +0000
@@ -1,15 +0,0 @@
-<!-- Copyright 2011 Canonical Ltd. This software is licensed under the
- GNU Affero General Public License version 3 (see the file LICENSE).
--->
-<configure
- xmlns="http://namespaces.zope.org/zope"
- xmlns:browser="http://namespaces.zope.org/browser"
- xmlns:i18n="http://namespaces.zope.org/i18n"
- i18n_domain="launchpad">
- <adapter factory=".adapters.storm.LongPollStormEvent" />
- <adapter factory=".adapters.storm.LongPollStormCreationEvent" />
- <adapter factory=".adapters.subscriber.LongPollApplicationRequestSubscriber" />
- <subscriber handler=".adapters.storm.object_created" />
- <subscriber handler=".adapters.storm.object_deleted" />
- <subscriber handler=".adapters.storm.object_modified" />
-</configure>
=== removed file 'lib/lp/services/longpoll/interfaces.py'
--- lib/lp/services/longpoll/interfaces.py 2011-09-20 19:04:19 +0000
+++ lib/lp/services/longpoll/interfaces.py 1970-01-01 00:00:00 +0000
@@ -1,64 +0,0 @@
-# Copyright 2011 Canonical Ltd. This software is licensed under the
-# GNU Affero General Public License version 3 (see the file LICENSE).
-
-"""Long-poll infrastructure interfaces."""
-
-__metaclass__ = type
-__all__ = [
- "ILongPollEvent",
- "ILongPollSubscriber",
- "long_poll_event",
- ]
-
-from zope.component import adapter
-from zope.interface import (
- Attribute,
- classImplements,
- Interface,
- )
-
-
-class ILongPollEvent(Interface):
-
- source = Attribute("The event source.")
-
- event_key = Attribute(
- "The key with which events will be emitted. Should be predictable "
- "and stable.")
-
- def emit(**data):
- """Emit the given data to `event_key`.
-
- :param data: Any data structures that can be dumped as JSON.
- """
-
-
-class ILongPollSubscriber(Interface):
-
- subscribe_key = Attribute(
- "The key which the subscriber must know in order to be able "
- "to long-poll for subscribed events. Should be infeasible to "
- "guess, a UUID for example.")
-
- def subscribe(event):
- """Subscribe to the given event.
-
- :type event: ILongPollEvent
- """
-
-
-def long_poll_event(source_spec):
- """Class decorator to declare an `ILongPollEvent`.
-
- :param source_spec: An interface or other specification understood by
- `zope.component` (a plain class can be passed too) that defines the
- source of an event. `IJob` or `storm.base.Storm` for example.
- """
- declare_adapter = adapter(source_spec)
-
- def declare_event(cls):
- classImplements(cls, ILongPollEvent)
- declare_adapter(cls)
- return cls
-
- return declare_event
=== removed file 'lib/lp/services/longpoll/testing.py'
--- lib/lp/services/longpoll/testing.py 2011-09-23 16:36:56 +0000
+++ lib/lp/services/longpoll/testing.py 1970-01-01 00:00:00 +0000
@@ -1,57 +0,0 @@
-# Copyright 2011 Canonical Ltd. This software is licensed under the
-# GNU Affero General Public License version 3 (see the file LICENSE).
-
-"""Things that help with testing of longpoll."""
-
-__metaclass__ = type
-__all__ = [
- "capture_longpoll_emissions",
- "LongPollEventRecord",
- ]
-
-from collections import namedtuple
-from contextlib import contextmanager
-from functools import partial
-
-from lp.services.longpoll.adapters import event
-
-
-LongPollEventRecord = namedtuple(
- "LongPollEventRecord", ("event_key", "data"))
-
-
-class LoggingRouter:
- """A test double for `IMessageProducer`.
-
- Saves messages as `LongPollEventRecord` tuples to a log.
-
- :param log: A callable accepting a single `LongPollEventRecord`.
- :param routing_key: See `IMessageSession.getProducer`.
- """
-
- def __init__(self, log, routing_key):
- self.log = log
- self.routing_key = routing_key
-
- def send(self, data):
- record = LongPollEventRecord(self.routing_key, data)
- self.log(record)
-
-
-@contextmanager
-def capture_longpoll_emissions():
- """Capture longpoll emissions while this context is in force.
-
- This returns a list in which `LongPollEventRecord` tuples will be
- recorded, in the order they're emitted.
-
- Note that normal event emission is *suppressed globally* while this
- context is in force; *all* events will be stored in the log.
- """
- log = []
- original_router_factory = event.router_factory
- event.router_factory = partial(LoggingRouter, log.append)
- try:
- yield log
- finally:
- event.router_factory = original_router_factory
=== removed directory 'lib/lp/services/longpoll/tests'
=== removed file 'lib/lp/services/longpoll/tests/__init__.py'
=== removed file 'lib/lp/services/longpoll/tests/test_interfaces.py'
--- lib/lp/services/longpoll/tests/test_interfaces.py 2011-09-20 19:04:19 +0000
+++ lib/lp/services/longpoll/tests/test_interfaces.py 1970-01-01 00:00:00 +0000
@@ -1,33 +0,0 @@
-# Copyright 2011 Canonical Ltd. This software is licensed under the
-# GNU Affero General Public License version 3 (see the file LICENSE).
-
-"""Long-poll interface tests."""
-
-__metaclass__ = type
-
-from zope.component import adaptedBy
-from zope.interface import Interface
-
-from lp.services.longpoll.interfaces import (
- ILongPollEvent,
- long_poll_event,
- )
-from lp.testing import TestCase
-
-
-class IEventSourceInterface(Interface):
- """Test interface for an event source."""
-
-
-class TestLongPollInterfaces(TestCase):
-
- def test_long_poll_event(self):
- # long_poll_event is a class decorator that declares a class as an
- # ILongPollEvent.
- @long_poll_event(IEventSourceInterface)
- class Something:
- """An example event source."""
- self.assertTrue(ILongPollEvent.implementedBy(Something))
- self.assertEqual(
- (IEventSourceInterface,),
- adaptedBy(Something))
=== removed directory 'lib/lp/services/txlongpoll'
=== removed file 'lib/lp/services/txlongpoll/__init__.py'
=== removed file 'lib/lp/services/txlongpoll/server.py'
--- lib/lp/services/txlongpoll/server.py 2011-09-30 07:28:45 +0000
+++ lib/lp/services/txlongpoll/server.py 1970-01-01 00:00:00 +0000
@@ -1,31 +0,0 @@
-# Copyright 2011 Canonical Ltd. This software is licensed under the
-# GNU Affero General Public License version 3 (see the file LICENSE).
-
-"""TxLongPoll server fixture."""
-
-__metaclass__ = type
-__all__ = [
- 'TxLongPollServer',
- ]
-
-from textwrap import dedent
-
-from txlongpollfixture.server import TxLongPollFixture
-
-
-class TxLongPollServer(TxLongPollFixture):
- """A TxLongPoll server fixture with Launchpad-specific config.
-
- :ivar service_config: A snippet of .ini that describes the `txlongpoll`
- configuration.
- """
-
- def setUp(self):
- super(TxLongPollServer, self).setUp()
- setattr(
- self, 'service_config',
- dedent("""\
- [txlongpoll]
- frontend_port: %d
- """ % (
- self.config.frontend_port)))
=== removed directory 'lib/lp/services/txlongpoll/tests'
=== removed file 'lib/lp/services/txlongpoll/tests/__init__.py'
=== removed file 'lib/lp/services/txlongpoll/tests/test_server.py'
--- lib/lp/services/txlongpoll/tests/test_server.py 2017-09-23 03:13:41 +0000
+++ lib/lp/services/txlongpoll/tests/test_server.py 1970-01-01 00:00:00 +0000
@@ -1,38 +0,0 @@
-# Copyright 2011-2017 Canonical Ltd. This software is licensed under the
-# GNU Affero General Public License version 3 (see the file LICENSE).
-
-"""Tests for lp.services.rabbit.TxLongPollServer."""
-
-__metaclass__ = type
-
-from ConfigParser import SafeConfigParser
-import os
-from StringIO import StringIO
-
-from lp.services.config import config
-from lp.services.txlongpoll.server import TxLongPollServer
-from lp.testing import TestCase
-from lp.testing.layers import RabbitMQLayer
-
-
-class TestTxLongPollServer(TestCase):
-
- layer = RabbitMQLayer
-
- def test_service_config(self):
- # TxLongPollServer pokes some .ini configuration into its
- # service_config attributes.
- twistd_bin = os.path.join(config.root, 'bin', 'twistd')
- fixture = self.useFixture(TxLongPollServer(
- broker_user='guest', broker_password='guest', broker_vhost='/',
- broker_port=123, frontend_port=None,
- twistd_bin=twistd_bin))
- service_config = SafeConfigParser()
- service_config.readfp(StringIO(getattr(fixture, 'service_config')))
- self.assertEqual(["txlongpoll"], service_config.sections())
- # txlongpoll section
- expected = {
- "frontend_port": "%d" % fixture.config.frontend_port,
- }
- observed = dict(service_config.items("txlongpoll"))
- self.assertEqual(expected, observed)
=== modified file 'setup.py'
--- setup.py 2018-07-16 10:51:04 +0000
+++ setup.py 2019-04-16 14:35:10 +0000
@@ -227,8 +227,6 @@
'treq',
'Twisted[conch,tls]',
'txfixtures',
- 'txlongpoll',
- 'txlongpollfixture',
'txpkgupload',
'virtualenv-tools3',
'wadllib',
Follow ups