Merge lp:~veebers/stock-ticker-mobile-app/mock-server-for-testing into lp:stock-ticker-mobile-app

Proposed by Christopher Lee on 2013-11-13
Status: Rejected
Rejected by: Nicholas Skaggs on 2014-05-01
Proposed branch: lp:~veebers/stock-ticker-mobile-app/mock-server-for-testing
Merge into: lp:stock-ticker-mobile-app
Prerequisite: lp:~veebers/stock-ticker-mobile-app/porting-autopilot-1.4
Diff against target: 313 lines (+196/-14)
4 files modified
Add_Stocks_page.qml (+2/-2)
Stock_Ticker.qml (+31/-4)
tests/autopilot/stock_ticker/mock_data_server.py (+144/-0)
tests/autopilot/stock_ticker/tests/__init__.py (+19/-8)
To merge this branch: bzr merge lp:~veebers/stock-ticker-mobile-app/mock-server-for-testing
Reviewer Review Type Date Requested Status
David Planella 2013-11-13 Disapprove on 2014-05-01
Nicholas Skaggs 2014-04-30 Pending
Review via email: mp+194971@code.launchpad.net

This proposal supersedes a proposal from 2013-11-13.

Description of the change

Introduce a mock http server for use in testing (no need to hit external network).
Modify application so that it can take a data source url as an argument (enabling use of the mock server).

To post a comment you must log in.
Nicholas Skaggs (nskaggs) wrote :

Veebers, any feedback from the developers?

Robert Steckroth (robertsteckroth) wrote :

I would need to take time off of work to do it. I almost had 3 days this
week, but... I should be available sooner than later.
I do not know how functional the mock server will be in development either.
The unit tests should not rely on application code. The application
run-time functions which switch the server url should be removed and a url
set in the autopilot.
Other than that, it will be difficult to get the merge through at its
current state.

On Mon, Dec 2, 2013 at 3:36 PM, Nicholas Skaggs <
<email address hidden>> wrote:

> Veebers, any feedback from the developers?
> --
>
> https://code.launchpad.net/~veebers/stock-ticker-mobile-app/mock-server-for-testing/+merge/194971
> Your team Stock Ticker Developers is requested to review the proposed
> merge of lp:~veebers/stock-ticker-mobile-app/mock-server-for-testing into
> lp:stock-ticker-mobile-app.
>

--
<surgemcgee> Systems/Software Engineer

Nicholas Skaggs (nskaggs) wrote :

Robert, any chance to further this? Sounds like you want to change how dataServerUrl is set?

Robert Steckroth (robertsteckroth) wrote :

I do have some extra time this week, hmm..

On Wed, Jan 22, 2014 at 5:01 PM, Nicholas Skaggs <
<email address hidden>> wrote:

> Robert, any chance to further this? Sounds like you want to change how
> dataServerUrl is set?
> --
>
> https://code.launchpad.net/~veebers/stock-ticker-mobile-app/mock-server-for-testing/+merge/194971
> Your team Stock Ticker Developers is requested to review the proposed
> merge of lp:~veebers/stock-ticker-mobile-app/mock-server-for-testing into
> lp:stock-ticker-mobile-app.
>

--
<surgemcgee>

This has been idle for some months now. Is it still relevant and will it be reviewed at soon?
It's one of our oldest merge requests.

Nicholas Skaggs (nskaggs) wrote :

It's contingent on what is happening from an application development standpoint. If the app is going to be changed, as suggested by Robert, the tests just need small tweaks to work. If it merges now, there's some qml changes that might not be in agreement with that.

Robert Steckroth (robertsteckroth) wrote :

That changeset was too ambitious. Also, I personally do not like the
offline unit testing setup. I will be adding Indurate database 1.3 support
soon and do not plan on incorporating that branch.
It is unfortunate however, as the python work was very professional.

On Wed, Apr 30, 2014 at 3:28 PM, Nicholas Skaggs <
<email address hidden>> wrote:

> It's contingent on what is happening from an application development
> standpoint. If the app is going to be changed, as suggested by Robert, the
> tests just need small tweaks to work. If it merges now, there's some qml
> changes that might not be in agreement with that.
> --
>
> https://code.launchpad.net/~veebers/stock-ticker-mobile-app/mock-server-for-testing/+merge/194971
> Your team Stock Ticker Developers is requested to review the proposed
> merge of lp:~veebers/stock-ticker-mobile-app/mock-server-for-testing into
> lp:stock-ticker-mobile-app.
>

--
<surgemcgee>

David Planella (dpm) wrote :

From the last comments, my recommendation would then be to mark the branch as Rejected. Christopher, please accept our apologies for the unresponsiveness on this branch. Feel free to reach out to me ('dpm'), popey or balloons on IRC for any questions.

review: Disapprove
Nicholas Skaggs (nskaggs) wrote :

I've rejected the merge, but think the code in mock_data_server.py is very useful as a reference.

Unmerged revisions

76. By Christopher Lee on 2013-11-13

Initial server working

75. By Christopher Lee on 2013-11-12

Further additions to assist in mocking server.

74. By Christopher Lee on 2013-11-12

Enable being able to use a different datasource.

Preview Diff

[H/L] Next/Prev Comment, [J/K] Next/Prev File, [N/P] Next/Prev Hunk
1=== modified file 'Add_Stocks_page.qml'
2--- Add_Stocks_page.qml 2013-08-28 03:15:07 +0000
3+++ Add_Stocks_page.qml 2013-11-13 02:26:42 +0000
4@@ -27,6 +27,7 @@
5 property string active_search_tick: ""
6 property string before_after_space: "00"
7 // This is used as two varibles > 0 is for has space at begining of line in `function update_search_text`
8+ property string dataServerUrl: "http://d.yimg.com/autoc.finance.yahoo.com/" // Can be overwritten for testing.
9
10 Timer {
11 id: reloadTrigger
12@@ -55,7 +56,6 @@
13
14 function text_change_handler() {
15 log("text_change_handler()")
16-
17 // Find the current word the user is editing by spaces before and after current word at cursor
18 var cursor_to_end = addStockTextField.text.substr(addStockTextField.cursorPosition).split(' ')
19 var cursor_to_begining = addStockTextField.text.substr(0, addStockTextField.cursorPosition+cursor_to_end[0].length).split(' ')
20@@ -73,7 +73,7 @@
21 matchIndicator = true
22 active_search_tick = search_word
23 before_after_space = before_after
24- xhr.open("GET","http://d.yimg.com/autoc.finance.yahoo.com/autoc?query="+search_word+"&callback=YAHOO.Finance.SymbolSuggest.ssCallback", true);
25+ xhr.open("GET", dataServerUrl + "autoc?query="+search_word+"&callback=YAHOO.Finance.SymbolSuggest.ssCallback", true);
26 xhr.onreadystatechange = function()
27 {
28 if ( xhr.readyState == xhr.DONE) {
29
30=== modified file 'Stock_Ticker.qml'
31--- Stock_Ticker.qml 2013-10-09 20:13:18 +0000
32+++ Stock_Ticker.qml 2013-11-13 02:26:42 +0000
33@@ -24,6 +24,17 @@
34
35
36 MainView {
37+ Arguments {
38+ id: args
39+
40+ Argument {
41+ name: "dataserver"
42+ help: "Server to use for retrieving data (Useful for testing.)"
43+ required: false
44+ valueNames: ["URL"]
45+ }
46+ }
47+
48 // objectName for functional testing purposes (autopilot-qt5)
49 objectName: "stockTicker"
50 applicationName: "com.ubuntu.stock-ticker-mobile"
51@@ -47,13 +58,26 @@
52
53 property int dummyTextWidth // Holds the width of the percent sign in Stock_Component_Main
54
55- property string serverDomain: "http://www.surgemcgee.com:8080/"
56-// property string serverDomain: "http://localhost:8080/"
57+ property string serverDomain: get_data_server() ? get_data_server() : "http://www.surgemcgee.com:8080/"
58+ property string dataServer: get_data_server() ? get_data_server() : "http://finance.yahoo.com/"
59
60 function log(message) {
61 console.log("["+applicationName+"] "+message)
62 }
63
64+ // If no dataserver argument passed returns undefined, otherwise returns a cleaned up URL.
65+ function get_data_server() {
66+ var server = args.values.dataserver;
67+ if (server === undefined)
68+ return undefined
69+ if (server.substr(0, 7) !== "http://")
70+ server = "http://" + server
71+ if (server.slice(-1) !== "/")
72+ server += "/"
73+
74+ return server
75+ }
76+
77 property string quoteParams: "?f=sabl1vpghojkc8dre7j1n&s="
78 property var database: new Store.IndurateDatabase({name: "SockTickerMobile", version: "1.0", description: "The Stock Ticker core application database", size: 4}, LocalStorage)
79 property var userTable: database.initTable(primaryTable, false, function(msg){ console.log(msg) })
80@@ -413,7 +437,7 @@
81
82 XmlListModel {
83 id: newsFeed
84- source: "http://finance.yahoo.com/rss/headline?s="+chartTick
85+ source: dataServer + "rss/headline?s=" +chartTick
86 query: "/rss/channel/item"
87 XmlRole { name: "title"; query: "title/string()" }
88 XmlRole { name: "description"; query: "description/string()" }
89@@ -672,7 +696,10 @@
90 width: parent.width - 10 // Subtract the main program border amount here
91 height: parent.height
92 anchors.horizontalCenter: parent.horizontalCenter
93- Add_Stocks_page { id: addStocksTab }
94+ Add_Stocks_page {
95+ id: addStocksTab
96+ dataServerUrl: get_data_server() ? get_data_server() : Add_Stocks_page.dataServerUrl
97+ }
98 }
99 }
100 }
101
102=== added file 'tests/autopilot/stock_ticker/mock_data_server.py'
103--- tests/autopilot/stock_ticker/mock_data_server.py 1970-01-01 00:00:00 +0000
104+++ tests/autopilot/stock_ticker/mock_data_server.py 2013-11-13 02:26:42 +0000
105@@ -0,0 +1,144 @@
106+# -*- Mode: Python; coding: utf-8; indent-tabs-mode: nil; tab-width: 4 -*-
107+#
108+# Copyright (C) 2013 Canonical Ltd
109+#
110+# This program is free software: you can redistribute it and/or modify
111+# it under the terms of the GNU General Public License version 3 as
112+# published by the Free Software Foundation.
113+#
114+# This program is distributed in the hope that it will be useful,
115+# but WITHOUT ANY WARRANTY; without even the implied warranty of
116+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
117+# GNU General Public License for more details.
118+#
119+# You should have received a copy of the GNU General Public License
120+# along with this program. If not, see <http://www.gnu.org/licenses/>.
121+
122+import BaseHTTPServer
123+import errno
124+import os
125+import socket
126+import threading
127+from textwrap import dedent
128+import re
129+
130+
131+class HTTPRequestHandler(BaseHTTPServer.BaseHTTPRequestHandler):
132+ """Simple HTTP request handler that mocks data and requests for testing."""
133+
134+ def _send_xml(self, xml):
135+ self.send_response(200)
136+ self.send_header("Content-Type", "application/xml")
137+ self.end_headers()
138+ self.wfile.write(
139+ '<?xml version="1.0" encoding="UTF-8"?>{content}'.format(
140+ content=xml
141+ )
142+ )
143+
144+ def _send_json(self, json):
145+ self.send_response(200)
146+ self.send_header(
147+ "Content-Type",
148+ "application/x-javascript; charset=utf-8"
149+ )
150+ self.end_headers()
151+ self.wfile.write(json)
152+
153+ def send_stock_data(self):
154+ match_check = re.compile("\&s=[\+]+goo")
155+ if match_check.search(self.path) is not None:
156+ google_stock_data = dedent(
157+ '<stockInfo>'
158+ '<currentStats stkent0="GOOG" '
159+ 'stkent1="1040.66" stkent2="1009.50" stkent3="1010.59" '
160+ 'stkent4="1112778" stkent5="1016.03" stkent6="1008.00" '
161+ 'stkent7="1015.93" stkent8="1009.51" stkent9="636.00" '
162+ 'stkent10="1041.52" stkent11="N/A - N/A" stkent12="0.00" '
163+ 'stkent13="27.65" stkent14="44.06" stkent15="337.6B" '
164+ 'stkent16="Google Inc."/>'
165+ '</stockInfo>'
166+ )
167+ self._send_xml(google_stock_data)
168+ else:
169+ self._send_xml('<stockInfo></stockInfo>')
170+
171+ def send_autocomplete_data(self):
172+ """Build up a response for the autocomplete.
173+
174+ Pad-out the wanted data with dummy data
175+
176+ """
177+ google_result = dedent(
178+ '{"symbol":"GOOG","name": "Google Inc.","exch": "NMS","type": "S",'
179+ '"exchDisp":"NASDAQ","typeDisp":"Equity"}'
180+ )
181+ dummy_result = dedent(
182+ '{"symbol":"DUMM","name": "Dummy Inc.","exch": "NMS","type": "S",'
183+ '"exchDisp":"NASDAQ","typeDisp":"Equity"}'
184+ )
185+ result_list = "{google},{dummies}".format(
186+ google=google_result,
187+ dummies=",".join([dummy_result for x in range(9)])
188+ )
189+ json = dedent(
190+ 'YAHOO.Finance.SymbolSuggest.ssCallback('
191+ '{"ResultSet":{"Query":"goo","Result":'
192+ '['
193+ '%s'
194+ ']}})'
195+ % result_list
196+ )
197+ self._send_json(json)
198+
199+ def do_GET(self):
200+ try:
201+ if self.path.startswith("/?f"):
202+ self.send_stock_data()
203+ elif self.path.startswith("/rss/2.0/headline"):
204+ self._send_xml('<rss version="2.0"><channel/></rss>')
205+ elif self.path.startswith("/autoc"):
206+ self.send_autocomplete_data()
207+ else:
208+ self.send_response(200)
209+ self.end_headers()
210+ self.wfile.write("[[[[ UNKNOWN ]]]]")
211+ except IOError as e:
212+ pass
213+
214+class HTTPServerInAThread(threading.Thread):
215+ """Simple custom HTTP server run in a separate thread."""
216+
217+ def __init__(self):
218+ super(HTTPServerInAThread, self).__init__()
219+ port = 12345
220+ self.server = None
221+ while self.server is None:
222+ try:
223+ self.server = BaseHTTPServer.HTTPServer(
224+ ("", port),
225+ HTTPRequestHandler
226+ )
227+ except socket.error as error:
228+ if (error.errno == errno.EADDRINUSE):
229+ print "Port %d is already in use" % port
230+ port += 1
231+ else:
232+ print os.strerror(error.errno)
233+ raise
234+ self.server.allow_reuse_address = True
235+
236+ @property
237+ def port(self):
238+ return self.server.server_port
239+
240+ def run(self):
241+ print "now serving on port %d" % self.port
242+ self.server.serve_forever()
243+
244+ def shutdown(self):
245+ self.server.shutdown()
246+ self.server.server_close()
247+
248+
249+__all__ = ["HTTPServerInAThread"]
250
251=== modified file 'tests/autopilot/stock_ticker/tests/__init__.py'
252--- tests/autopilot/stock_ticker/tests/__init__.py 2013-11-13 02:26:41 +0000
253+++ tests/autopilot/stock_ticker/tests/__init__.py 2013-11-13 02:26:42 +0000
254@@ -26,7 +26,7 @@
255 from autopilot.testcase import AutopilotTestCase
256
257 from ubuntuuitoolkit import emulators as toolkit_emulators
258-from stock_ticker import emulators
259+from stock_ticker import emulators, mock_data_server
260
261 logger = logging.getLogger(__name__)
262
263@@ -54,32 +54,43 @@
264 self.temp_move_sqlite_db()
265 self.addCleanup(self.restore_sqlite_db)
266
267+ self.server = mock_data_server.HTTPServerInAThread()
268+ self.server.start()
269+ self.addCleanup(self.server.shutdown)
270+
271+ url = self._get_data_server_url()
272 if os.path.exists(self.local_location):
273- self.launch_test_local()
274+ self.launch_test_local(url)
275 elif os.path.exists(self.installed_location):
276- self.launch_test_installed()
277+ self.launch_test_installed(url)
278 else:
279- self.launch_test_click()
280-
281- def launch_test_local(self):
282+ self.launch_test_click(url)
283+
284+ def _get_data_server_url(self):
285+ return "http://localhost:%s" % self.server.port
286+
287+ def launch_test_local(self, server_url):
288 self.app = self.launch_test_application(
289 "qmlscene",
290 self.local_location,
291+ "--dataserver=%s" % server_url,
292 app_type='qt',
293 emulator_base=toolkit_emulators.UbuntuUIToolkitEmulatorBase)
294
295- def launch_test_installed(self):
296+ def launch_test_installed(self, server_url):
297 self.app = self.launch_test_application(
298 "qmlscene",
299 self.installed_location,
300 "--desktop_file_hint=/usr/share/applications/"
301 "stock-ticker-app.desktop",
302+ "--dataserver=%s" % server_url,
303 app_type='qt',
304 emulator_base=toolkit_emulators.UbuntuUIToolkitEmulatorBase)
305
306- def launch_test_click(self):
307+ def launch_test_click(self, server_url):
308 self.app = self.launch_click_package(
309 "com.ubuntu.stock-ticker-mobile",
310+ "--dataserver=%s" % server_url,
311 emulator_base=toolkit_emulators.UbuntuUIToolkitEmulatorBase)
312
313 def temp_move_sqlite_db(self):

Subscribers

People subscribed via source and target branches