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

Proposed by Christopher Lee
Status: Rejected
Rejected by: Nicholas Skaggs
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 Disapprove
Nicholas Skaggs 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.
Revision history for this message
Nicholas Skaggs (nskaggs) wrote :

Veebers, any feedback from the developers?

Revision history for this message
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

Revision history for this message
Nicholas Skaggs (nskaggs) wrote :

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

Revision history for this message
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>

Revision history for this message
Alan Pope 🍺🐧🐱 πŸ¦„ (popey) wrote :

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.

Revision history for this message
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.

Revision history for this message
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>

Revision history for this message
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
Revision history for this message
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

Initial server working

75. By Christopher Lee

Further additions to assist in mocking server.

74. By Christopher Lee

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
=== modified file 'Add_Stocks_page.qml'
--- Add_Stocks_page.qml 2013-08-28 03:15:07 +0000
+++ Add_Stocks_page.qml 2013-11-13 02:26:42 +0000
@@ -27,6 +27,7 @@
27 property string active_search_tick: ""27 property string active_search_tick: ""
28 property string before_after_space: "00"28 property string before_after_space: "00"
29 // This is used as two varibles > 0 is for has space at begining of line in `function update_search_text`29 // This is used as two varibles > 0 is for has space at begining of line in `function update_search_text`
30 property string dataServerUrl: "http://d.yimg.com/autoc.finance.yahoo.com/" // Can be overwritten for testing.
3031
31 Timer {32 Timer {
32 id: reloadTrigger33 id: reloadTrigger
@@ -55,7 +56,6 @@
5556
56 function text_change_handler() {57 function text_change_handler() {
57 log("text_change_handler()")58 log("text_change_handler()")
58
59 // Find the current word the user is editing by spaces before and after current word at cursor59 // Find the current word the user is editing by spaces before and after current word at cursor
60 var cursor_to_end = addStockTextField.text.substr(addStockTextField.cursorPosition).split(' ')60 var cursor_to_end = addStockTextField.text.substr(addStockTextField.cursorPosition).split(' ')
61 var cursor_to_begining = addStockTextField.text.substr(0, addStockTextField.cursorPosition+cursor_to_end[0].length).split(' ')61 var cursor_to_begining = addStockTextField.text.substr(0, addStockTextField.cursorPosition+cursor_to_end[0].length).split(' ')
@@ -73,7 +73,7 @@
73 matchIndicator = true73 matchIndicator = true
74 active_search_tick = search_word74 active_search_tick = search_word
75 before_after_space = before_after75 before_after_space = before_after
76 xhr.open("GET","http://d.yimg.com/autoc.finance.yahoo.com/autoc?query="+search_word+"&callback=YAHOO.Finance.SymbolSuggest.ssCallback", true);76 xhr.open("GET", dataServerUrl + "autoc?query="+search_word+"&callback=YAHOO.Finance.SymbolSuggest.ssCallback", true);
77 xhr.onreadystatechange = function()77 xhr.onreadystatechange = function()
78 {78 {
79 if ( xhr.readyState == xhr.DONE) {79 if ( xhr.readyState == xhr.DONE) {
8080
=== modified file 'Stock_Ticker.qml'
--- Stock_Ticker.qml 2013-10-09 20:13:18 +0000
+++ Stock_Ticker.qml 2013-11-13 02:26:42 +0000
@@ -24,6 +24,17 @@
2424
2525
26MainView {26MainView {
27 Arguments {
28 id: args
29
30 Argument {
31 name: "dataserver"
32 help: "Server to use for retrieving data (Useful for testing.)"
33 required: false
34 valueNames: ["URL"]
35 }
36 }
37
27 // objectName for functional testing purposes (autopilot-qt5)38 // objectName for functional testing purposes (autopilot-qt5)
28 objectName: "stockTicker"39 objectName: "stockTicker"
29 applicationName: "com.ubuntu.stock-ticker-mobile"40 applicationName: "com.ubuntu.stock-ticker-mobile"
@@ -47,13 +58,26 @@
4758
48 property int dummyTextWidth // Holds the width of the percent sign in Stock_Component_Main59 property int dummyTextWidth // Holds the width of the percent sign in Stock_Component_Main
4960
50 property string serverDomain: "http://www.surgemcgee.com:8080/"61 property string serverDomain: get_data_server() ? get_data_server() : "http://www.surgemcgee.com:8080/"
51// property string serverDomain: "http://localhost:8080/"62 property string dataServer: get_data_server() ? get_data_server() : "http://finance.yahoo.com/"
5263
53 function log(message) {64 function log(message) {
54 console.log("["+applicationName+"] "+message)65 console.log("["+applicationName+"] "+message)
55 }66 }
5667
68 // If no dataserver argument passed returns undefined, otherwise returns a cleaned up URL.
69 function get_data_server() {
70 var server = args.values.dataserver;
71 if (server === undefined)
72 return undefined
73 if (server.substr(0, 7) !== "http://")
74 server = "http://" + server
75 if (server.slice(-1) !== "/")
76 server += "/"
77
78 return server
79 }
80
57 property string quoteParams: "?f=sabl1vpghojkc8dre7j1n&s="81 property string quoteParams: "?f=sabl1vpghojkc8dre7j1n&s="
58 property var database: new Store.IndurateDatabase({name: "SockTickerMobile", version: "1.0", description: "The Stock Ticker core application database", size: 4}, LocalStorage)82 property var database: new Store.IndurateDatabase({name: "SockTickerMobile", version: "1.0", description: "The Stock Ticker core application database", size: 4}, LocalStorage)
59 property var userTable: database.initTable(primaryTable, false, function(msg){ console.log(msg) })83 property var userTable: database.initTable(primaryTable, false, function(msg){ console.log(msg) })
@@ -413,7 +437,7 @@
413437
414 XmlListModel {438 XmlListModel {
415 id: newsFeed439 id: newsFeed
416 source: "http://finance.yahoo.com/rss/headline?s="+chartTick440 source: dataServer + "rss/headline?s=" +chartTick
417 query: "/rss/channel/item"441 query: "/rss/channel/item"
418 XmlRole { name: "title"; query: "title/string()" }442 XmlRole { name: "title"; query: "title/string()" }
419 XmlRole { name: "description"; query: "description/string()" }443 XmlRole { name: "description"; query: "description/string()" }
@@ -672,7 +696,10 @@
672 width: parent.width - 10 // Subtract the main program border amount here696 width: parent.width - 10 // Subtract the main program border amount here
673 height: parent.height697 height: parent.height
674 anchors.horizontalCenter: parent.horizontalCenter698 anchors.horizontalCenter: parent.horizontalCenter
675 Add_Stocks_page { id: addStocksTab }699 Add_Stocks_page {
700 id: addStocksTab
701 dataServerUrl: get_data_server() ? get_data_server() : Add_Stocks_page.dataServerUrl
702 }
676 }703 }
677 }704 }
678 }705 }
679706
=== added file 'tests/autopilot/stock_ticker/mock_data_server.py'
--- tests/autopilot/stock_ticker/mock_data_server.py 1970-01-01 00:00:00 +0000
+++ tests/autopilot/stock_ticker/mock_data_server.py 2013-11-13 02:26:42 +0000
@@ -0,0 +1,144 @@
1# -*- Mode: Python; coding: utf-8; indent-tabs-mode: nil; tab-width: 4 -*-
2#
3# Copyright (C) 2013 Canonical Ltd
4#
5# This program is free software: you can redistribute it and/or modify
6# it under the terms of the GNU General Public License version 3 as
7# published by the Free Software Foundation.
8#
9# This program is distributed in the hope that it will be useful,
10# but WITHOUT ANY WARRANTY; without even the implied warranty of
11# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12# GNU General Public License for more details.
13#
14# You should have received a copy of the GNU General Public License
15# along with this program. If not, see <http://www.gnu.org/licenses/>.
16
17import BaseHTTPServer
18import errno
19import os
20import socket
21import threading
22from textwrap import dedent
23import re
24
25
26class HTTPRequestHandler(BaseHTTPServer.BaseHTTPRequestHandler):
27 """Simple HTTP request handler that mocks data and requests for testing."""
28
29 def _send_xml(self, xml):
30 self.send_response(200)
31 self.send_header("Content-Type", "application/xml")
32 self.end_headers()
33 self.wfile.write(
34 '<?xml version="1.0" encoding="UTF-8"?>{content}'.format(
35 content=xml
36 )
37 )
38
39 def _send_json(self, json):
40 self.send_response(200)
41 self.send_header(
42 "Content-Type",
43 "application/x-javascript; charset=utf-8"
44 )
45 self.end_headers()
46 self.wfile.write(json)
47
48 def send_stock_data(self):
49 match_check = re.compile("\&s=[\+]+goo")
50 if match_check.search(self.path) is not None:
51 google_stock_data = dedent(
52 '<stockInfo>'
53 '<currentStats stkent0="GOOG" '
54 'stkent1="1040.66" stkent2="1009.50" stkent3="1010.59" '
55 'stkent4="1112778" stkent5="1016.03" stkent6="1008.00" '
56 'stkent7="1015.93" stkent8="1009.51" stkent9="636.00" '
57 'stkent10="1041.52" stkent11="N/A - N/A" stkent12="0.00" '
58 'stkent13="27.65" stkent14="44.06" stkent15="337.6B" '
59 'stkent16="Google Inc."/>'
60 '</stockInfo>'
61 )
62 self._send_xml(google_stock_data)
63 else:
64 self._send_xml('<stockInfo></stockInfo>')
65
66 def send_autocomplete_data(self):
67 """Build up a response for the autocomplete.
68
69 Pad-out the wanted data with dummy data
70
71 """
72 google_result = dedent(
73 '{"symbol":"GOOG","name": "Google Inc.","exch": "NMS","type": "S",'
74 '"exchDisp":"NASDAQ","typeDisp":"Equity"}'
75 )
76 dummy_result = dedent(
77 '{"symbol":"DUMM","name": "Dummy Inc.","exch": "NMS","type": "S",'
78 '"exchDisp":"NASDAQ","typeDisp":"Equity"}'
79 )
80 result_list = "{google},{dummies}".format(
81 google=google_result,
82 dummies=",".join([dummy_result for x in range(9)])
83 )
84 json = dedent(
85 'YAHOO.Finance.SymbolSuggest.ssCallback('
86 '{"ResultSet":{"Query":"goo","Result":'
87 '['
88 '%s'
89 ']}})'
90 % result_list
91 )
92 self._send_json(json)
93
94 def do_GET(self):
95 try:
96 if self.path.startswith("/?f"):
97 self.send_stock_data()
98 elif self.path.startswith("/rss/2.0/headline"):
99 self._send_xml('<rss version="2.0"><channel/></rss>')
100 elif self.path.startswith("/autoc"):
101 self.send_autocomplete_data()
102 else:
103 self.send_response(200)
104 self.end_headers()
105 self.wfile.write("[[[[ UNKNOWN ]]]]")
106 except IOError as e:
107 pass
108
109class HTTPServerInAThread(threading.Thread):
110 """Simple custom HTTP server run in a separate thread."""
111
112 def __init__(self):
113 super(HTTPServerInAThread, self).__init__()
114 port = 12345
115 self.server = None
116 while self.server is None:
117 try:
118 self.server = BaseHTTPServer.HTTPServer(
119 ("", port),
120 HTTPRequestHandler
121 )
122 except socket.error as error:
123 if (error.errno == errno.EADDRINUSE):
124 print "Port %d is already in use" % port
125 port += 1
126 else:
127 print os.strerror(error.errno)
128 raise
129 self.server.allow_reuse_address = True
130
131 @property
132 def port(self):
133 return self.server.server_port
134
135 def run(self):
136 print "now serving on port %d" % self.port
137 self.server.serve_forever()
138
139 def shutdown(self):
140 self.server.shutdown()
141 self.server.server_close()
142
143
144__all__ = ["HTTPServerInAThread"]
0145
=== modified file 'tests/autopilot/stock_ticker/tests/__init__.py'
--- tests/autopilot/stock_ticker/tests/__init__.py 2013-11-13 02:26:41 +0000
+++ tests/autopilot/stock_ticker/tests/__init__.py 2013-11-13 02:26:42 +0000
@@ -26,7 +26,7 @@
26from autopilot.testcase import AutopilotTestCase26from autopilot.testcase import AutopilotTestCase
2727
28from ubuntuuitoolkit import emulators as toolkit_emulators28from ubuntuuitoolkit import emulators as toolkit_emulators
29from stock_ticker import emulators29from stock_ticker import emulators, mock_data_server
3030
31logger = logging.getLogger(__name__)31logger = logging.getLogger(__name__)
3232
@@ -54,32 +54,43 @@
54 self.temp_move_sqlite_db()54 self.temp_move_sqlite_db()
55 self.addCleanup(self.restore_sqlite_db)55 self.addCleanup(self.restore_sqlite_db)
5656
57 self.server = mock_data_server.HTTPServerInAThread()
58 self.server.start()
59 self.addCleanup(self.server.shutdown)
60
61 url = self._get_data_server_url()
57 if os.path.exists(self.local_location):62 if os.path.exists(self.local_location):
58 self.launch_test_local()63 self.launch_test_local(url)
59 elif os.path.exists(self.installed_location):64 elif os.path.exists(self.installed_location):
60 self.launch_test_installed()65 self.launch_test_installed(url)
61 else:66 else:
62 self.launch_test_click()67 self.launch_test_click(url)
6368
64 def launch_test_local(self):69 def _get_data_server_url(self):
70 return "http://localhost:%s" % self.server.port
71
72 def launch_test_local(self, server_url):
65 self.app = self.launch_test_application(73 self.app = self.launch_test_application(
66 "qmlscene",74 "qmlscene",
67 self.local_location,75 self.local_location,
76 "--dataserver=%s" % server_url,
68 app_type='qt',77 app_type='qt',
69 emulator_base=toolkit_emulators.UbuntuUIToolkitEmulatorBase)78 emulator_base=toolkit_emulators.UbuntuUIToolkitEmulatorBase)
7079
71 def launch_test_installed(self):80 def launch_test_installed(self, server_url):
72 self.app = self.launch_test_application(81 self.app = self.launch_test_application(
73 "qmlscene",82 "qmlscene",
74 self.installed_location,83 self.installed_location,
75 "--desktop_file_hint=/usr/share/applications/"84 "--desktop_file_hint=/usr/share/applications/"
76 "stock-ticker-app.desktop",85 "stock-ticker-app.desktop",
86 "--dataserver=%s" % server_url,
77 app_type='qt',87 app_type='qt',
78 emulator_base=toolkit_emulators.UbuntuUIToolkitEmulatorBase)88 emulator_base=toolkit_emulators.UbuntuUIToolkitEmulatorBase)
7989
80 def launch_test_click(self):90 def launch_test_click(self, server_url):
81 self.app = self.launch_click_package(91 self.app = self.launch_click_package(
82 "com.ubuntu.stock-ticker-mobile",92 "com.ubuntu.stock-ticker-mobile",
93 "--dataserver=%s" % server_url,
83 emulator_base=toolkit_emulators.UbuntuUIToolkitEmulatorBase)94 emulator_base=toolkit_emulators.UbuntuUIToolkitEmulatorBase)
8495
85 def temp_move_sqlite_db(self):96 def temp_move_sqlite_db(self):

Subscribers

People subscribed via source and target branches