From 729d7d2815366a8e5d838963c658f7c193ebc66a Mon Sep 17 00:00:00 2001
From: Alain Takoudjou <alain.takoudjou@nexedi.com>
Date: Wed, 30 Aug 2017 10:18:07 +0000
Subject: [PATCH] [officejs_monitoring_test] Add test for monitor interface
 navigation

---
 .../portal_tests/web_monitoring_ui_zuite.xml  |  26 ++
 .../testMonitoringSyncNavigation.xml          |  58 +++
 .../testMonitoringSyncNavigation.zpt          | 372 ++++++++++++++++++
 ...t.erp5.testFunctionalOfficejsMonitoring.py | 311 +++++++++++++++
 ....erp5.testFunctionalOfficejsMonitoring.xml | 125 ++++++
 .../bt/copyright_list                         |   1 +
 .../bt/dependency_list                        |   3 +
 .../bt/description                            |   1 +
 bt5/erp5_web_monitoring_ui_test/bt/license    |   1 +
 .../bt/template_format_version                |   1 +
 .../bt/template_path_list                     |   2 +
 .../bt/template_test_id_list                  |   1 +
 .../bt/test_dependency_list                   |   1 +
 bt5/erp5_web_monitoring_ui_test/bt/title      |   1 +
 bt5/erp5_web_monitoring_ui_test/bt/version    |   1 +
 15 files changed, 905 insertions(+)
 create mode 100644 bt5/erp5_web_monitoring_ui_test/PathTemplateItem/portal_tests/web_monitoring_ui_zuite.xml
 create mode 100644 bt5/erp5_web_monitoring_ui_test/PathTemplateItem/portal_tests/web_monitoring_ui_zuite/testMonitoringSyncNavigation.xml
 create mode 100644 bt5/erp5_web_monitoring_ui_test/PathTemplateItem/portal_tests/web_monitoring_ui_zuite/testMonitoringSyncNavigation.zpt
 create mode 100644 bt5/erp5_web_monitoring_ui_test/TestTemplateItem/portal_components/test.erp5.testFunctionalOfficejsMonitoring.py
 create mode 100644 bt5/erp5_web_monitoring_ui_test/TestTemplateItem/portal_components/test.erp5.testFunctionalOfficejsMonitoring.xml
 create mode 100644 bt5/erp5_web_monitoring_ui_test/bt/copyright_list
 create mode 100644 bt5/erp5_web_monitoring_ui_test/bt/dependency_list
 create mode 100644 bt5/erp5_web_monitoring_ui_test/bt/description
 create mode 100644 bt5/erp5_web_monitoring_ui_test/bt/license
 create mode 100644 bt5/erp5_web_monitoring_ui_test/bt/template_format_version
 create mode 100644 bt5/erp5_web_monitoring_ui_test/bt/template_path_list
 create mode 100644 bt5/erp5_web_monitoring_ui_test/bt/template_test_id_list
 create mode 100644 bt5/erp5_web_monitoring_ui_test/bt/test_dependency_list
 create mode 100644 bt5/erp5_web_monitoring_ui_test/bt/title
 create mode 100644 bt5/erp5_web_monitoring_ui_test/bt/version

diff --git a/bt5/erp5_web_monitoring_ui_test/PathTemplateItem/portal_tests/web_monitoring_ui_zuite.xml b/bt5/erp5_web_monitoring_ui_test/PathTemplateItem/portal_tests/web_monitoring_ui_zuite.xml
new file mode 100644
index 0000000000..17f636aeba
--- /dev/null
+++ b/bt5/erp5_web_monitoring_ui_test/PathTemplateItem/portal_tests/web_monitoring_ui_zuite.xml
@@ -0,0 +1,26 @@
+<?xml version="1.0"?>
+<ZopeData>
+  <record id="1" aka="AAAAAAAAAAE=">
+    <pickle>
+      <global name="Zuite" module="Products.Zelenium.zuite"/>
+    </pickle>
+    <pickle>
+      <dictionary>
+        <item>
+            <key> <string>_objects</string> </key>
+            <value>
+              <tuple/>
+            </value>
+        </item>
+        <item>
+            <key> <string>id</string> </key>
+            <value> <string>web_monitoring_ui_zuite</string> </value>
+        </item>
+        <item>
+            <key> <string>title</string> </key>
+            <value> <string></string> </value>
+        </item>
+      </dictionary>
+    </pickle>
+  </record>
+</ZopeData>
diff --git a/bt5/erp5_web_monitoring_ui_test/PathTemplateItem/portal_tests/web_monitoring_ui_zuite/testMonitoringSyncNavigation.xml b/bt5/erp5_web_monitoring_ui_test/PathTemplateItem/portal_tests/web_monitoring_ui_zuite/testMonitoringSyncNavigation.xml
new file mode 100644
index 0000000000..56dc7c72fe
--- /dev/null
+++ b/bt5/erp5_web_monitoring_ui_test/PathTemplateItem/portal_tests/web_monitoring_ui_zuite/testMonitoringSyncNavigation.xml
@@ -0,0 +1,58 @@
+<?xml version="1.0"?>
+<ZopeData>
+  <record id="1" aka="AAAAAAAAAAE=">
+    <pickle>
+      <global name="ZopePageTemplate" module="Products.PageTemplates.ZopePageTemplate"/>
+    </pickle>
+    <pickle>
+      <dictionary>
+        <item>
+            <key> <string>_bind_names</string> </key>
+            <value>
+              <object>
+                <klass>
+                  <global name="NameAssignments" module="Shared.DC.Scripts.Bindings"/>
+                </klass>
+                <tuple/>
+                <state>
+                  <dictionary>
+                    <item>
+                        <key> <string>_asgns</string> </key>
+                        <value>
+                          <dictionary>
+                            <item>
+                                <key> <string>name_subpath</string> </key>
+                                <value> <string>traverse_subpath</string> </value>
+                            </item>
+                          </dictionary>
+                        </value>
+                    </item>
+                  </dictionary>
+                </state>
+              </object>
+            </value>
+        </item>
+        <item>
+            <key> <string>content_type</string> </key>
+            <value> <string>text/html</string> </value>
+        </item>
+        <item>
+            <key> <string>expand</string> </key>
+            <value> <int>0</int> </value>
+        </item>
+        <item>
+            <key> <string>id</string> </key>
+            <value> <string>testMonitoringSyncNavigation</string> </value>
+        </item>
+        <item>
+            <key> <string>output_encoding</string> </key>
+            <value> <string>utf-8</string> </value>
+        </item>
+        <item>
+            <key> <string>title</string> </key>
+            <value> <unicode></unicode> </value>
+        </item>
+      </dictionary>
+    </pickle>
+  </record>
+</ZopeData>
diff --git a/bt5/erp5_web_monitoring_ui_test/PathTemplateItem/portal_tests/web_monitoring_ui_zuite/testMonitoringSyncNavigation.zpt b/bt5/erp5_web_monitoring_ui_test/PathTemplateItem/portal_tests/web_monitoring_ui_zuite/testMonitoringSyncNavigation.zpt
new file mode 100644
index 0000000000..82d34dde96
--- /dev/null
+++ b/bt5/erp5_web_monitoring_ui_test/PathTemplateItem/portal_tests/web_monitoring_ui_zuite/testMonitoringSyncNavigation.zpt
@@ -0,0 +1,372 @@
+<html xmlns:tal="http://xml.zope.org/namespaces/tal"
+      xmlns:metal="http://xml.zope.org/namespaces/metal">
+<head>
+<meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
+<title>Test SlapOS Monitoring UI (expected failure)</title>
+</head>
+<body>
+<table cellpadding="1" cellspacing="1" border="1">
+<thead>
+<tr><td rowspan="1" colspan="3">Test SlapOS Monitoring UI (expected failure)</td></tr>
+</thead><tbody>
+<tal:block metal:use-macro="here/Zuite_CommonTemplate/macros/init" />
+<!-- Clean Up -->
+<tr>
+  <td>open</td>
+  <td>${base_url}/bar_module/ListBoxZuite_reset</td>
+  <td></td>
+</tr>
+<tr>
+  <td>assertTextPresent</td>
+  <td>Reset Successfully.</td>
+  <td></td>
+</tr>
+<!-- Initialize -->
+<tr>
+  <td>open</td>
+  <td>${base_url}/web_site_module/monitoring_render_js/</td>
+  <td></td>
+</tr>
+<tr>
+  <td>waitForElementPresent</td>
+  <td>//button[@data-i18n='Menu']</td>
+  <td></td>
+</tr>
+<tr>
+  <td>click</td>
+  <td>//a[@href='#page=settings_configurator']</td>
+  <td></td>
+</tr>
+<tr>
+  <td>waitForElementPresent</td>
+  <td>//span[@data-i18n="Configure monitoring OPML"]</td>
+  <td></td>
+</tr>
+<tr>
+  <td>click</td>
+  <td>//a[@href='#config-add']</td>
+  <td></td>
+</tr>
+<tr>
+  <td>pause</td>
+  <td>500</td>
+  <td></td>
+</tr>
+<tr>
+  <td>assertElementPresent</td>
+  <td>//button[@data-i18n='Add OPML']</td>
+  <td></td>
+</tr>
+<tr>
+  <td>store</td>
+  <td>http://localhost:5378/rootInstance/public/feeds</td>
+  <td>opml_url</td>
+</tr>
+<tr>
+  <td>store</td>
+  <td>admin</td>
+  <td>username</td>
+</tr>
+<tr>
+  <td>store</td>
+  <td>zwkuyjdl</td>
+  <td>password</td>
+</tr>
+<tr>
+  <td>type</td>
+  <td>name=url</td>
+  <td>${opml_url}</td>
+</tr>
+<tr>
+  <td>type</td>
+  <td>name=username</td>
+  <td>${username}</td>
+</tr>
+<tr>
+  <td>type</td>
+  <td>name=password</td>
+  <td>${password}</td>
+</tr>
+<tr>
+  <td>click</td>
+  <td>//button[@data-i18n='Add OPML']</td>
+  <td></td>
+</tr>
+<tr>
+  <td>pause</td>
+  <td>1000</td>
+  <td></td>
+</tr>
+<tr>
+  <td>assertTextNotPresent</td>
+  <td>Failed to access OPML URL</td>
+  <td></td>
+</tr>
+<tr>
+  <td>pause</td>
+  <td>500</td>
+  <td></td>
+</tr>
+<tr>
+  <td>waitForTextPresent</td>
+  <td>Monitoring Promises Status</td>
+  <td></td>
+</tr>
+<tr>
+  <td>assertElementPresent</td>
+  <td>//button[contains(@class, 'sync-all')]</td>
+  <td></td>
+</tr>
+<tr>
+  <td>click</td>
+  <td>//a[@href='#page=settings_configurator']</td>
+  <td></td>
+</tr>
+<tr>
+  <td>pause</td>
+  <td>2000</td>
+  <td></td>
+</tr>
+<tr>
+  <td>assertElementPresent</td>
+  <td>//table[contains(@class, 'opml-tablelinks')]</td>
+  <td></td>
+</tr>
+<tr>
+  <td>assertTextPresent</td>
+  <td>${opml_url}</td>
+  <td></td>
+</tr>
+<tr>
+  <td>storeElementPresent</td>
+  <td>//table[contains(@class, 'opml-tablelinks')]/tbody/tr[1]/td[3]/a</td>
+  <td>has_hosting</td>
+</tr>
+<tr>
+  <td>storeText</td>
+  <td>//table[contains(@class, 'opml-tablelinks')]/tbody/tr[1]/td[3]/a</td>
+  <td>hosting_title</td>
+</tr>
+<tr>
+  <td>click</td>
+  <td>//button[contains(@class, 'sync-all')]</td>
+  <td></td>
+</tr>
+<tr>
+  <td>waitForTextPresent</td>
+  <td>Synchronizing Data...</td>
+  <td></td>
+</tr>
+<tr>
+  <td>waitForTextPresent</td>
+  <td>Synchronisation finished</td>
+  <td></td>
+</tr>
+<tr>
+  <td>click</td>
+  <td>//a[@href='#page=hosting_subscription_list']</td>
+  <td></td>
+</tr>
+<tr>
+  <td>pause</td>
+  <td>2000</td>
+  <td></td>
+</tr>
+<tr>
+  <td>assertTextPresent</td>
+  <td>${hosting_title}</td>
+  <td></td>
+</tr>
+<tr>
+  <td>click</td>
+  <td>//table[contains(@class, 'instance-overview')]/tbody/tr[1]/td[1]/a</td>
+  <td></td>
+</tr>
+<tr>
+  <td>pause</td>
+  <td>2000</td>
+  <td></td>
+</tr>
+<tr>
+  <td>assertTextPresent</td>
+  <td>${hosting_title}</td>
+  <td></td>
+</tr>
+<tr>
+  <td>open</td>
+  <td>${base_url}/web_site_module/monitoring_render_js/app/</td>
+  <td></td>
+</tr>
+<tr>
+  <td>waitForElementPresent</td>
+  <td>//button[@data-i18n='Menu']</td>
+  <td></td>
+</tr>
+<tr>
+  <td>pause</td>
+  <td>500</td>
+  <td></td>
+</tr>
+<tr>
+  <td>assertElementPresent</td>
+  <td>//span[@data-i18n="Monitoring Promises Status"]</td>
+  <td></td>
+</tr>
+<tr>
+  <td>assertTextPresent</td>
+  <td>${hosting_title}</td>
+  <td></td>
+</tr>
+<tr>
+  <td>click</td>
+  <td>//table[contains(@class, 'ui-responsive')]/tbody/tr[1]/td[1]/a</td>
+  <td></td>
+</tr>
+<tr>
+  <td>waitForElementPresent</td>
+  <td>//button[@data-i18n='Menu']</td>
+  <td></td>
+</tr>
+<tr>
+  <td>pause</td>
+  <td>2000</td>
+  <td></td>
+</tr>
+<tr>
+  <td>open</td>
+  <td>${base_url}/web_page_module/Zuite_waitForActivities</td>
+  <td></td>
+</tr>
+<tr>
+  <td>assertTextPresent</td>
+  <td>Done.</td>
+  <td></td>
+</tr>
+<tr>
+  <td>open</td>
+  <td>${base_url}/web_site_module/monitoring_render_js/app/#page=settings_configurator</td>
+  <td></td>
+</tr>
+<tr>
+  <td>waitForElementPresent</td>
+  <td>//button[@data-i18n='Menu']</td>
+  <td></td>
+</tr>
+<tr>
+  <td>pause</td>
+  <td>500</td>
+  <td></td>
+</tr>
+<tr>
+  <td>click</td>
+  <td>//table[contains(@class, 'opml-tablelinks')]/tbody/tr[1]/td[3]/a</td>
+  <td></td>
+</tr>
+<tr>
+  <td>pause</td>
+  <td>500</td>
+  <td></td>
+</tr>
+<tr>
+  <td>waitForElementPresent</td>
+  <td>//button[@data-i18n='Add OPML']</td>
+  <td></td>
+</tr>
+<tr>
+  <td>click</td>
+  <td>//label[contains(@class, 'configure-auth')]</td>
+  <td></td>
+</tr>
+<tr>
+  <td>pause</td>
+  <td>500</td>
+  <td></td>
+</tr>
+<tr>
+  <td>assertElementPresent</td>
+  <td>//label[@data-i18n="Confirm New Password:"]</td>
+  <td></td>
+</tr>
+<tr>
+  <td>type</td>
+  <td>name=new_password_confirm</td>
+  <td>${password}</td>
+</tr>
+<tr>
+  <td>type</td>
+  <td>name=new_password</td>
+  <td>${password}</td>
+</tr>
+<tr>
+  <td>click</td>
+  <td>//button[@data-i18n='Add OPML']</td>
+  <td></td>
+</tr>
+<tr>
+  <td>pause</td>
+  <td>2000</td>
+  <td></td>
+</tr>
+<tr>
+  <td>assertElementPresent</td>
+  <td>//button[contains(@class, 'sync-all')]</td>
+  <td></td>
+</tr>
+<tr>
+  <td>click</td>
+  <td>//button[contains(@class, 'sync-all')]</td>
+  <td></td>
+</tr>
+<tr>
+  <td>waitForTextPresent</td>
+  <td>Synchronizing Data...</td>
+  <td></td>
+</tr>
+<tr>
+  <td>waitForTextPresent</td>
+  <td>Synchronisation finished</td>
+  <td></td>
+</tr>
+<tr>
+  <td>click</td>
+  <td>//input[@name='opml-all']</td>
+  <td></td>
+</tr>
+<tr>
+  <td>clickAndWait</td>
+  <td>//a[contains(@class, 'opml-delete')]</td>
+  <td></td>
+</tr>
+<tr>
+  <td>waitForElementPresent</td>
+  <td>//button[@data-i18n='Menu']</td>
+  <td></td>
+</tr>
+<tr>
+  <td>pause</td>
+  <td>500</td>
+  <td></td>
+</tr>
+<tr>
+  <td>assertTextNotPresent</td>
+  <td>${opml_url}</td>
+  <td></td>
+</tr>
+<tr>
+  <td>click</td>
+  <td>//a[@href='#page=hosting_subscription_list']</td>
+  <td></td>
+</tr>
+<tr>
+  <td>pause</td>
+  <td>2000</td>
+  <td></td>
+</tr>
+<tr>
+  <td>assertTextNotPresent</td>
+  <td>${hosting_title}</td>
+  <td></td>
+</tr>
+</tbody></table>
+</body>
+</html>
\ No newline at end of file
diff --git a/bt5/erp5_web_monitoring_ui_test/TestTemplateItem/portal_components/test.erp5.testFunctionalOfficejsMonitoring.py b/bt5/erp5_web_monitoring_ui_test/TestTemplateItem/portal_components/test.erp5.testFunctionalOfficejsMonitoring.py
new file mode 100644
index 0000000000..143d5299fe
--- /dev/null
+++ b/bt5/erp5_web_monitoring_ui_test/TestTemplateItem/portal_components/test.erp5.testFunctionalOfficejsMonitoring.py
@@ -0,0 +1,311 @@
+##############################################################################
+#
+# Copyright (c) 2011 Nexedi SARL and Contributors. All Rights Reserved.
+#
+# WARNING: This program as such is intended to be used by professional
+# programmers who take the whole responsability of assessing all potential
+# consequences resulting from its eventual inadequacies and bugs
+# End users who are looking for a ready-to-use solution with commercial
+# garantees and support are strongly adviced to contract a Free Software
+# Service Company
+#
+# This program is Free Software; you can redistribute it and/or
+# modify it under the terms of the GNU General Public License
+# as published by the Free Software Foundation; either version 2
+# of the License, or (at your option) any later version.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with this program; if not, write to the Free Software
+# Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
+#
+##############################################################################
+import unittest
+
+from Products.ERP5Type.tests.ERP5TypeFunctionalTestCase import ERP5TypeFunctionalTestCase
+from SimpleHTTPServer import SimpleHTTPRequestHandler
+from threading import Thread
+from datetime import datetime
+
+import SocketServer
+import tempfile
+import shutil
+import time
+import os
+import json
+
+class CustomHTTPRequestHandler(SimpleHTTPRequestHandler):
+  def end_headers(self):
+    self.send_my_headers()
+
+    SimpleHTTPRequestHandler.end_headers(self)
+
+  def send_respond(self, code=200, content_type='text/html'):
+    self.send_response(code)
+    self.send_header("Content-type", content_type)
+    self.end_headers()
+
+  def send_my_headers(self):
+    self.send_header("Access-Control-Allow-Origin", "*")
+    self.send_header("Access-Control-Allow-Methods", "HEAD, OPTIONS, GET, POST")
+    self.send_header("Access-Control-Allow-Headers", "Overwrite, Destination, Content-Type, Depth, User-Agent, X-File-Size, X-Requested-With, If-Modified-Since, X-File-Name, Cache-Control, Authorization")
+
+  def do_GET(self):
+    SimpleHTTPRequestHandler.do_GET(self)
+
+  def do_OPTIONS(self):
+    self.send_respond(200)
+
+  def do_HEAD(self):
+    self.send_respond()
+
+class TestZeleniumCore(ERP5TypeFunctionalTestCase):
+  foreground = 0
+  run_only = "web_monitoring_ui_zuite"
+  base_url = 'http://localhost:5378'
+  instance_list = []
+  httpd = None
+  httpd_is_alive = False
+  root_title = "TEST Hosting Subscription"
+
+  def start_httpd_server(self, root_folder):
+    self.httpd = SocketServer.TCPServer(('localhost', 5378), CustomHTTPRequestHandler)
+    self.httpd.timeout = 2
+    os.chdir(root_folder)
+    #self.httpd.serve_forever()
+    while self.httpd_is_alive:
+      self.httpd.handle_request()
+
+    self.httpd = None
+
+  def afterSetUp(self):
+    ERP5TypeFunctionalTestCase.afterSetUp(self)
+
+    self.http_root_dir = tempfile.mkdtemp()
+    print "Serving files on http from %r" % self.http_root_dir
+
+    self.generateMonitoringInstanceTree()
+    self.httpd_is_alive = True
+    thread = Thread(target=self.start_httpd_server, args=(self.http_root_dir,))
+    thread.daemon = True
+    thread.start()
+
+  def beforeTearDown(self):
+    self.httpd_is_alive = False
+    # Wait for httpd server stop
+    time.sleep(3)
+    if os.path.exists(self.http_root_dir):
+      shutil.rmtree(self.http_root_dir)
+    ERP5TypeFunctionalTestCase.beforeTearDown(self)
+
+  def getBusinessTemplateList(self):
+    return (
+      'erp5_ui_test',
+      'erp5_web_monitoring',
+      'erp5_ui_test_core',
+      )
+
+  def generateInstanceDirectory(self, name):
+    root_dir = os.path.join(self.http_root_dir, name)
+    public_http_dir = os.path.join(root_dir, 'public')
+    private_http_dir = os.path.join(root_dir, 'private')
+    webdav_http_dir = os.path.join(root_dir, 'share')
+    os.mkdir(root_dir)
+    os.mkdir(public_http_dir)
+    os.mkdir(private_http_dir)
+    os.mkdir(webdav_http_dir)
+
+    webdav_public_dir = os.path.join(webdav_http_dir, 'public')
+    webdav_private_dir = os.path.join(webdav_http_dir, 'private')
+
+    os.symlink(public_http_dir, webdav_public_dir)
+    os.symlink(private_http_dir, webdav_private_dir)
+
+    instance = dict(
+      title=name,
+      public_dir=public_http_dir,
+      private_dir=private_http_dir,
+      url=self.base_url + '/' + name
+    )
+    self.instance_list.append(instance)
+    return instance
+
+  def generatePromiseResult(self, instance, status='OK', amount=1):
+    now_time = time.time()
+    start_date = time.strftime("%Y-%m-%d %H:%M:%S", time.localtime(time.time()))
+
+    for i in range(0, amount):
+      title = 'test_promise_%s' % i
+      result_dict = {
+        "status": status,
+        "change-time": now_time,
+        "hosting_subscription": self.root_title,
+        "title": title,
+        "start-date": start_date,
+        "instance": instance['title'],
+        "_links": {
+          "monitor": {
+            "href": "%s/share/private/" % instance['url']
+          }
+        },
+        "message": "Test Promise ran with status %s" % status,
+        "type": "status"
+      }
+      with open(os.path.join(instance['public_dir'], '%s.json' % title), 'w') as f:
+        f.write(json.dumps(result_dict))
+
+  def generateOPMLFile(self, instance, sub_instance_list=[]):
+    creation_date = datetime.utcnow().strftime("%a, %d %b %Y %H:%M:%S +0000")
+    opml_content = """<?xml version="1.0" encoding="UTF-8"?>
+<!-- OPML generated by SlapOS -->
+<opml version="1.1">
+	<head>
+		<title>%(root_title)s</title>
+		<dateCreated>%(creation_date)s</dateCreated>
+		<dateModified>%(creation_date)s</dateModified>
+	</head>
+	<body>
+	  <outline text="Monitoring RSS Feed list">""" % {
+	    "root_title": self.root_title,
+	    "creation_date": creation_date
+	  }
+    opml_content += '\n<outline text="%(title)s" title="%(title)s" type="rss" version="RSS" htmlUrl="%(html_url)s" xmlUrl="%(html_url)s" url="%(global_url)s" />' % {
+	    "title": instance['title'],
+	    "html_url": '%s/public/feed' % instance['url'],
+	    "global_url": "%s/share/private/" % instance['url'],
+    }
+    for sub_instance in sub_instance_list:
+      opml_content += '\n<outline text="%(title)s" title="%(title)s" type="rss" version="RSS" htmlUrl="%(html_url)s" xmlUrl="%(html_url)s" url="%(global_url)s" />' % {
+  	    "title": sub_instance['title'],
+  	    "html_url": '%s/public/feed' % sub_instance['url'],
+  	    "global_url": "%s/share/private/" % sub_instance['url'],
+      }
+
+    opml_content += """	  </outline>
+  </body>
+</opml>"""
+
+    with open(os.path.join(instance['public_dir'], 'feeds'), 'w') as f:
+      f.write(opml_content)
+
+
+  def generateInstanceRssFeed(self, instance):
+    promise_list = [name.rstrip('.json')
+      for name in os.listdir(instance['public_dir']) if name.endswith('.json')]
+    rss_content = """<rss version="2.0">
+<channel>
+<title>%(instance)s</title>
+<link>%(link)s</link>
+<description>%(description)s</description>
+<lastBuildDate>%(date)s</lastBuildDate>
+<docs>http://blogs.law.harvard.edu/tech/rss</docs>""" % {
+      "description": self.root_title,
+      "link": '%s/public/feed' % instance['url'],
+      "instance": instance['title'],
+      "date": datetime.utcnow().strftime("%a, %d %b %Y %H:%M:%S +0000")
+    }
+
+    for promise in promise_list:
+      item = """<item>
+<title>%(title)s</title>
+<link>
+%(base_url)s/share/private/
+</link>
+<description>%(description)s</description>
+<category>%(status)s</category>
+<comments/>
+<guid isPermaLink="false">VU5LTk9XTiwgc2xhcHJ1bm5l%(id)s==</guid>
+<pubDate>%(date)s</pubDate>
+<source url="%(base_url)s/share/public/">%(title)s</source>
+</item>""" % {
+        "base_url": instance['url'],
+        "title": promise,
+        "status": "OK",
+        "description": "description of %s" % promise,
+        "id": int(time.time()),
+        "date": datetime.utcnow().strftime("%a, %d %b %Y %H:%M:%S +0000")
+      }
+
+      rss_content += item
+
+    rss_content += """</channel></rss>"""
+
+    with open(os.path.join(instance['public_dir'], 'feed'), 'w') as f:
+      f.write(rss_content.replace('\n', ''))
+
+  def generateMonitoringStatusFile(self, instance, status="OK"):
+    monitor_dict = {
+        "status": status,
+        "state": {
+          "warning": 0,
+          "success": 3,
+          "error": 0
+        },
+        "title": instance['title'],
+        "date": datetime.now().strftime('%Y-%m-%d %H:%M:%S'),
+        "data": {
+          "process_state": "monitor_process_resource.status",
+          "io_resource": "monitor_resource_io.data",
+          "state": "monitor_state.data",
+          "memory_resource": "monitor_resource_memory.data",
+          "process_resource": "monitor_resource_process.data",
+          "monitor_process_state": "monitor_resource.status"
+        },
+        "hosting-title": self.root_title,
+        "type": "global",
+        "_embedded": {
+          "instance": {
+            "partition": "slappart1",
+            "ipv6": "2001:67c:1254:e:c4::c748",
+            "computer": "slaprunner",
+            "ipv4": "10.0.165.37",
+            "software-release": "http://xxx.yyy.zz/asoftware/software.cfg",
+            "software-type": "pull-backup"
+          }
+        },
+        "parameters": [{"title": "demo", "value": "some parameter", "key": ""}],
+        "_links": {
+          "rss_url": {
+            "href": "%s/public/feed" % instance['url']
+          },
+          "public_url": {
+            "href": "%s/share/public/" % instance['url']
+          },
+          "private_url": {
+            "href": "%s/share/private/" % instance['url']
+          }
+        }
+      }
+
+    with open(os.path.join(instance['private_dir'], 'monitor.global.json'), 'w') as f:
+      f.write(json.dumps(monitor_dict))
+    with open(os.path.join(instance['private_dir'], '_document_list'), 'w') as f:
+      f.write("monitor.global")
+
+  def generateMonitoringInstanceTree(self):
+    # root instance
+    root_instance = self.generateInstanceDirectory("rootInstance")
+    self.generatePromiseResult(root_instance, status='OK', amount=5)
+    self.generateInstanceRssFeed(root_instance)
+    self.generateMonitoringStatusFile(root_instance, status='OK')
+    # sub instance1
+    sub_instance1 = self.generateInstanceDirectory("subInstance-1")
+    self.generatePromiseResult(sub_instance1, status='ERROR', amount=4)
+    self.generateInstanceRssFeed(sub_instance1)
+    self.generateMonitoringStatusFile(sub_instance1, status='ERROR')
+    # sub instance2
+    sub_instance2 = self.generateInstanceDirectory("subInstance-2")
+    self.generatePromiseResult(sub_instance2, status='OK', amount=7)
+    self.generateInstanceRssFeed(sub_instance2)
+    self.generateMonitoringStatusFile(sub_instance2, status='OK')
+
+    self.generateOPMLFile(root_instance, [sub_instance1, sub_instance2])
+
+def test_suite():
+  suite = unittest.TestSuite()
+  suite.addTest(unittest.makeSuite(TestZeleniumCore))
+  return suite
\ No newline at end of file
diff --git a/bt5/erp5_web_monitoring_ui_test/TestTemplateItem/portal_components/test.erp5.testFunctionalOfficejsMonitoring.xml b/bt5/erp5_web_monitoring_ui_test/TestTemplateItem/portal_components/test.erp5.testFunctionalOfficejsMonitoring.xml
new file mode 100644
index 0000000000..3e354b3d15
--- /dev/null
+++ b/bt5/erp5_web_monitoring_ui_test/TestTemplateItem/portal_components/test.erp5.testFunctionalOfficejsMonitoring.xml
@@ -0,0 +1,125 @@
+<?xml version="1.0"?>
+<ZopeData>
+  <record id="1" aka="AAAAAAAAAAE=">
+    <pickle>
+      <global name="Test Component" module="erp5.portal_type"/>
+    </pickle>
+    <pickle>
+      <dictionary>
+        <item>
+            <key> <string>_recorded_property_dict</string> </key>
+            <value>
+              <persistent> <string encoding="base64">AAAAAAAAAAI=</string> </persistent>
+            </value>
+        </item>
+        <item>
+            <key> <string>default_reference</string> </key>
+            <value> <string>testFunctionalOfficejsMonitoring</string> </value>
+        </item>
+        <item>
+            <key> <string>description</string> </key>
+            <value>
+              <none/>
+            </value>
+        </item>
+        <item>
+            <key> <string>id</string> </key>
+            <value> <string>test.erp5.testFunctionalOfficejsMonitoring</string> </value>
+        </item>
+        <item>
+            <key> <string>portal_type</string> </key>
+            <value> <string>Test Component</string> </value>
+        </item>
+        <item>
+            <key> <string>sid</string> </key>
+            <value>
+              <none/>
+            </value>
+        </item>
+        <item>
+            <key> <string>text_content_error_message</string> </key>
+            <value>
+              <tuple/>
+            </value>
+        </item>
+        <item>
+            <key> <string>text_content_warning_message</string> </key>
+            <value>
+              <tuple>
+                <string>W:161,  2: Dangerous default value [] as argument (dangerous-default-value)</string>
+              </tuple>
+            </value>
+        </item>
+        <item>
+            <key> <string>version</string> </key>
+            <value> <string>erp5</string> </value>
+        </item>
+        <item>
+            <key> <string>workflow_history</string> </key>
+            <value>
+              <persistent> <string encoding="base64">AAAAAAAAAAM=</string> </persistent>
+            </value>
+        </item>
+      </dictionary>
+    </pickle>
+  </record>
+  <record id="2" aka="AAAAAAAAAAI=">
+    <pickle>
+      <global name="PersistentMapping" module="Persistence.mapping"/>
+    </pickle>
+    <pickle>
+      <dictionary>
+        <item>
+            <key> <string>data</string> </key>
+            <value>
+              <dictionary/>
+            </value>
+        </item>
+      </dictionary>
+    </pickle>
+  </record>
+  <record id="3" aka="AAAAAAAAAAM=">
+    <pickle>
+      <global name="PersistentMapping" module="Persistence.mapping"/>
+    </pickle>
+    <pickle>
+      <dictionary>
+        <item>
+            <key> <string>data</string> </key>
+            <value>
+              <dictionary>
+                <item>
+                    <key> <string>component_validation_workflow</string> </key>
+                    <value>
+                      <persistent> <string encoding="base64">AAAAAAAAAAQ=</string> </persistent>
+                    </value>
+                </item>
+              </dictionary>
+            </value>
+        </item>
+      </dictionary>
+    </pickle>
+  </record>
+  <record id="4" aka="AAAAAAAAAAQ=">
+    <pickle>
+      <global name="WorkflowHistoryList" module="Products.ERP5Type.patches.WorkflowTool"/>
+    </pickle>
+    <pickle>
+      <tuple>
+        <none/>
+        <list>
+          <dictionary>
+            <item>
+                <key> <string>action</string> </key>
+                <value> <string>validate</string> </value>
+            </item>
+            <item>
+                <key> <string>validation_state</string> </key>
+                <value> <string>validated</string> </value>
+            </item>
+          </dictionary>
+        </list>
+      </tuple>
+    </pickle>
+  </record>
+</ZopeData>
diff --git a/bt5/erp5_web_monitoring_ui_test/bt/copyright_list b/bt5/erp5_web_monitoring_ui_test/bt/copyright_list
new file mode 100644
index 0000000000..5250404070
--- /dev/null
+++ b/bt5/erp5_web_monitoring_ui_test/bt/copyright_list
@@ -0,0 +1 @@
+Copyright (C) 2016 Nexedi SA
\ No newline at end of file
diff --git a/bt5/erp5_web_monitoring_ui_test/bt/dependency_list b/bt5/erp5_web_monitoring_ui_test/bt/dependency_list
new file mode 100644
index 0000000000..bd8266d0d5
--- /dev/null
+++ b/bt5/erp5_web_monitoring_ui_test/bt/dependency_list
@@ -0,0 +1,3 @@
+erp5_ui_test_core
+erp5_ui_test
+erp5_web_monitoring
\ No newline at end of file
diff --git a/bt5/erp5_web_monitoring_ui_test/bt/description b/bt5/erp5_web_monitoring_ui_test/bt/description
new file mode 100644
index 0000000000..658486f0b5
--- /dev/null
+++ b/bt5/erp5_web_monitoring_ui_test/bt/description
@@ -0,0 +1 @@
+Officejs Monitoring ui test
\ No newline at end of file
diff --git a/bt5/erp5_web_monitoring_ui_test/bt/license b/bt5/erp5_web_monitoring_ui_test/bt/license
new file mode 100644
index 0000000000..3a3e12bcad
--- /dev/null
+++ b/bt5/erp5_web_monitoring_ui_test/bt/license
@@ -0,0 +1 @@
+GPL
\ No newline at end of file
diff --git a/bt5/erp5_web_monitoring_ui_test/bt/template_format_version b/bt5/erp5_web_monitoring_ui_test/bt/template_format_version
new file mode 100644
index 0000000000..56a6051ca2
--- /dev/null
+++ b/bt5/erp5_web_monitoring_ui_test/bt/template_format_version
@@ -0,0 +1 @@
+1
\ No newline at end of file
diff --git a/bt5/erp5_web_monitoring_ui_test/bt/template_path_list b/bt5/erp5_web_monitoring_ui_test/bt/template_path_list
new file mode 100644
index 0000000000..85a032b6f2
--- /dev/null
+++ b/bt5/erp5_web_monitoring_ui_test/bt/template_path_list
@@ -0,0 +1,2 @@
+portal_tests/web_monitoring_ui_zuite
+portal_tests/web_monitoring_ui_zuite/**
\ No newline at end of file
diff --git a/bt5/erp5_web_monitoring_ui_test/bt/template_test_id_list b/bt5/erp5_web_monitoring_ui_test/bt/template_test_id_list
new file mode 100644
index 0000000000..b3e8be37ab
--- /dev/null
+++ b/bt5/erp5_web_monitoring_ui_test/bt/template_test_id_list
@@ -0,0 +1 @@
+test.erp5.testFunctionalOfficejsMonitoring
\ No newline at end of file
diff --git a/bt5/erp5_web_monitoring_ui_test/bt/test_dependency_list b/bt5/erp5_web_monitoring_ui_test/bt/test_dependency_list
new file mode 100644
index 0000000000..bff77e32d8
--- /dev/null
+++ b/bt5/erp5_web_monitoring_ui_test/bt/test_dependency_list
@@ -0,0 +1 @@
+erp5_full_text_mroonga_catalog
\ No newline at end of file
diff --git a/bt5/erp5_web_monitoring_ui_test/bt/title b/bt5/erp5_web_monitoring_ui_test/bt/title
new file mode 100644
index 0000000000..9b501691ba
--- /dev/null
+++ b/bt5/erp5_web_monitoring_ui_test/bt/title
@@ -0,0 +1 @@
+erp5_web_monitoring_ui_test
\ No newline at end of file
diff --git a/bt5/erp5_web_monitoring_ui_test/bt/version b/bt5/erp5_web_monitoring_ui_test/bt/version
new file mode 100644
index 0000000000..ceab6e11ec
--- /dev/null
+++ b/bt5/erp5_web_monitoring_ui_test/bt/version
@@ -0,0 +1 @@
+0.1
\ No newline at end of file
-- 
2.30.9