From c710da8c84d83b47942415b971f93431532e67cd Mon Sep 17 00:00:00 2001
From: Alain Takoudjou <talino@tiolive.com>
Date: Thu, 31 Jul 2014 17:11:24 +0200
Subject: [PATCH] Slapos pdm: Alarm create upgrade decision for hosting
 subscription

---
 ...g_subscription_create_upgrade_decision.xml | 111 +++++++++++++++++
 ...s_pdm_computer_create_upgrade_decision.xml |   8 +-
 ...omputerCheckUpgradeHostingSubscription.xml |  83 +++++++++++++
 ...Computer_checkAndCreateUpgradeDecision.xml |   2 +-
 ...stingSubscriptionCreateUpgradeDecision.xml | 116 ++++++++++++++++++
 .../SoftwareRelease_createUpgradeDecision.xml |  21 ++--
 ...areRelease_isUpgradeDecisionInProgress.xml |  11 +-
 .../TestTemplateItem/testSlapOSPDMAlarm.py    |  44 ++++++-
 .../TestTemplateItem/testSlapOSPDMSkins.py    | 106 +++++++++++++++-
 master/bt5/slapos_pdm/bt/revision             |   2 +-
 master/bt5/slapos_pdm/bt/template_path_list   |   1 +
 11 files changed, 485 insertions(+), 20 deletions(-)
 create mode 100644 master/bt5/slapos_pdm/PathTemplateItem/portal_alarms/slapos_hosting_subscription_create_upgrade_decision.xml
 create mode 100644 master/bt5/slapos_pdm/SkinTemplateItem/portal_skins/slapos_pdm/Alarm_computerCheckUpgradeHostingSubscription.xml
 create mode 100644 master/bt5/slapos_pdm/SkinTemplateItem/portal_skins/slapos_pdm/Computer_hostingSubscriptionCreateUpgradeDecision.xml

diff --git a/master/bt5/slapos_pdm/PathTemplateItem/portal_alarms/slapos_hosting_subscription_create_upgrade_decision.xml b/master/bt5/slapos_pdm/PathTemplateItem/portal_alarms/slapos_hosting_subscription_create_upgrade_decision.xml
new file mode 100644
index 000000000..a50720fcb
--- /dev/null
+++ b/master/bt5/slapos_pdm/PathTemplateItem/portal_alarms/slapos_hosting_subscription_create_upgrade_decision.xml
@@ -0,0 +1,111 @@
+<?xml version="1.0"?>
+<ZopeData>
+  <record id="1" aka="AAAAAAAAAAE=">
+    <pickle>
+      <global name="Alarm" module="erp5.portal_type"/>
+    </pickle>
+    <pickle>
+      <dictionary>
+        <item>
+            <key> <string>active_sense_method_id</string> </key>
+            <value> <string>Alarm_computerCheckUpgradeHostingSubscription</string> </value>
+        </item>
+        <item>
+            <key> <string>description</string> </key>
+            <value> <string>Create Upgrade Decision for computers to upgrade Hosting Subscriptions to a newer version.</string> </value>
+        </item>
+        <item>
+            <key> <string>enabled</string> </key>
+            <value> <int>0</int> </value>
+        </item>
+        <item>
+            <key> <string>id</string> </key>
+            <value> <string>slapos_hosting_subscription_create_upgrade_decision</string> </value>
+        </item>
+        <item>
+            <key> <string>periodicity_day_frequency</string> </key>
+            <value> <int>1</int> </value>
+        </item>
+        <item>
+            <key> <string>periodicity_hour</string> </key>
+            <value>
+              <tuple>
+                <int>0</int>
+              </tuple>
+            </value>
+        </item>
+        <item>
+            <key> <string>periodicity_hour_frequency</string> </key>
+            <value>
+              <none/>
+            </value>
+        </item>
+        <item>
+            <key> <string>periodicity_minute</string> </key>
+            <value>
+              <tuple>
+                <int>0</int>
+              </tuple>
+            </value>
+        </item>
+        <item>
+            <key> <string>periodicity_minute_frequency</string> </key>
+            <value>
+              <none/>
+            </value>
+        </item>
+        <item>
+            <key> <string>periodicity_month</string> </key>
+            <value>
+              <tuple/>
+            </value>
+        </item>
+        <item>
+            <key> <string>periodicity_month_day</string> </key>
+            <value>
+              <tuple/>
+            </value>
+        </item>
+        <item>
+            <key> <string>periodicity_start_date</string> </key>
+            <value>
+              <object>
+                <klass>
+                  <global name="DateTime" module="DateTime.DateTime"/>
+                </klass>
+                <tuple>
+                  <none/>
+                </tuple>
+                <state>
+                  <tuple>
+                    <float>1406073600.0</float>
+                    <string>GMT</string>
+                  </tuple>
+                </state>
+              </object>
+            </value>
+        </item>
+        <item>
+            <key> <string>periodicity_week</string> </key>
+            <value>
+              <tuple/>
+            </value>
+        </item>
+        <item>
+            <key> <string>portal_type</string> </key>
+            <value> <string>Alarm</string> </value>
+        </item>
+        <item>
+            <key> <string>sense_method_id</string> </key>
+            <value>
+              <none/>
+            </value>
+        </item>
+        <item>
+            <key> <string>title</string> </key>
+            <value> <string>Create Upgrade Decision for Hosting Subscriptions</string> </value>
+        </item>
+      </dictionary>
+    </pickle>
+  </record>
+</ZopeData>
diff --git a/master/bt5/slapos_pdm/PathTemplateItem/portal_alarms/slapos_pdm_computer_create_upgrade_decision.xml b/master/bt5/slapos_pdm/PathTemplateItem/portal_alarms/slapos_pdm_computer_create_upgrade_decision.xml
index 52030e826..1a260c6a7 100644
--- a/master/bt5/slapos_pdm/PathTemplateItem/portal_alarms/slapos_pdm_computer_create_upgrade_decision.xml
+++ b/master/bt5/slapos_pdm/PathTemplateItem/portal_alarms/slapos_pdm_computer_create_upgrade_decision.xml
@@ -22,6 +22,10 @@
             <key> <string>id</string> </key>
             <value> <string>slapos_pdm_computer_create_upgrade_decision</string> </value>
         </item>
+        <item>
+            <key> <string>periodicity_day_frequency</string> </key>
+            <value> <int>1</int> </value>
+        </item>
         <item>
             <key> <string>periodicity_hour</string> </key>
             <value>
@@ -59,9 +63,7 @@
         <item>
             <key> <string>periodicity_month_day</string> </key>
             <value>
-              <tuple>
-                <int>1</int>
-              </tuple>
+              <tuple/>
             </value>
         </item>
         <item>
diff --git a/master/bt5/slapos_pdm/SkinTemplateItem/portal_skins/slapos_pdm/Alarm_computerCheckUpgradeHostingSubscription.xml b/master/bt5/slapos_pdm/SkinTemplateItem/portal_skins/slapos_pdm/Alarm_computerCheckUpgradeHostingSubscription.xml
new file mode 100644
index 000000000..2a5abf946
--- /dev/null
+++ b/master/bt5/slapos_pdm/SkinTemplateItem/portal_skins/slapos_pdm/Alarm_computerCheckUpgradeHostingSubscription.xml
@@ -0,0 +1,83 @@
+<?xml version="1.0"?>
+<ZopeData>
+  <record id="1" aka="AAAAAAAAAAE=">
+    <pickle>
+      <global name="PythonScript" module="Products.PythonScripts.PythonScript"/>
+    </pickle>
+    <pickle>
+      <dictionary>
+        <item>
+            <key> <string>Script_magic</string> </key>
+            <value> <int>3</int> </value>
+        </item>
+        <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_container</string> </key>
+                                <value> <string>container</string> </value>
+                            </item>
+                            <item>
+                                <key> <string>name_context</string> </key>
+                                <value> <string>context</string> </value>
+                            </item>
+                            <item>
+                                <key> <string>name_m_self</string> </key>
+                                <value> <string>script</string> </value>
+                            </item>
+                            <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>_body</string> </key>
+            <value> <string>portal = context.getPortalObject()\n
+\n
+public_scope_uid = portal.restrictedTraverse(\n
+  "portal_categories/allocation_scope/open/public", None).getUid()\n
+friend_scope_uid =  portal.restrictedTraverse(\n
+  "portal_categories/allocation_scope/open/friend", None).getUid()\n
+\n
+if public_scope_uid and friend_scope_uid:\n
+  portal.portal_catalog.searchAndActivate(\n
+    portal_type=\'Computer\',\n
+    validation_state = \'validated\',\n
+    default_allocation_scope_uid=[public_scope_uid, friend_scope_uid],\n
+    method_id = \'Computer_hostingSubscriptionCreateUpgradeDecision\',\n
+    activate_kw = {\'tag\':tag}\n
+  )\n
+  \n
+  context.activate(after_tag=tag).getId()\n
+</string> </value>
+        </item>
+        <item>
+            <key> <string>_params</string> </key>
+            <value> <string>tag, fixit, params</string> </value>
+        </item>
+        <item>
+            <key> <string>id</string> </key>
+            <value> <string>Alarm_computerCheckUpgradeHostingSubscription</string> </value>
+        </item>
+      </dictionary>
+    </pickle>
+  </record>
+</ZopeData>
diff --git a/master/bt5/slapos_pdm/SkinTemplateItem/portal_skins/slapos_pdm/Computer_checkAndCreateUpgradeDecision.xml b/master/bt5/slapos_pdm/SkinTemplateItem/portal_skins/slapos_pdm/Computer_checkAndCreateUpgradeDecision.xml
index c30009ef1..da36fa802 100644
--- a/master/bt5/slapos_pdm/SkinTemplateItem/portal_skins/slapos_pdm/Computer_checkAndCreateUpgradeDecision.xml
+++ b/master/bt5/slapos_pdm/SkinTemplateItem/portal_skins/slapos_pdm/Computer_checkAndCreateUpgradeDecision.xml
@@ -88,7 +88,7 @@ for software_release in software_release_list:\n
       continue\n
   \n
     return newer_release.SoftwareRelease_createUpgradeDecision(\n
-        computer_url=computer.getRelativeUrl(), title=title\n
+        source_url=computer.getRelativeUrl(), title=title\n
       )\n
 </string> </value>
         </item>
diff --git a/master/bt5/slapos_pdm/SkinTemplateItem/portal_skins/slapos_pdm/Computer_hostingSubscriptionCreateUpgradeDecision.xml b/master/bt5/slapos_pdm/SkinTemplateItem/portal_skins/slapos_pdm/Computer_hostingSubscriptionCreateUpgradeDecision.xml
new file mode 100644
index 000000000..0dbe13132
--- /dev/null
+++ b/master/bt5/slapos_pdm/SkinTemplateItem/portal_skins/slapos_pdm/Computer_hostingSubscriptionCreateUpgradeDecision.xml
@@ -0,0 +1,116 @@
+<?xml version="1.0"?>
+<ZopeData>
+  <record id="1" aka="AAAAAAAAAAE=">
+    <pickle>
+      <global name="PythonScript" module="Products.PythonScripts.PythonScript"/>
+    </pickle>
+    <pickle>
+      <dictionary>
+        <item>
+            <key> <string>Script_magic</string> </key>
+            <value> <int>3</int> </value>
+        </item>
+        <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_container</string> </key>
+                                <value> <string>container</string> </value>
+                            </item>
+                            <item>
+                                <key> <string>name_context</string> </key>
+                                <value> <string>context</string> </value>
+                            </item>
+                            <item>
+                                <key> <string>name_m_self</string> </key>
+                                <value> <string>script</string> </value>
+                            </item>
+                            <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>_body</string> </key>
+            <value> <string>computer = context\n
+portal = context.getPortalObject()\n
+\n
+partition_list = portal.portal_catalog(portal_type=\'Computer Partition\',\n
+                                        free_for_request=0,\n
+                                        parent_uid=computer.getUid())\n
+\n
+# Get Hosting Subscription for all allocated partition\n
+hosting_subscription_list = []\n
+for partition in partition_list:\n
+  software_instance = partition.getAggregateRelatedValue(\n
+                            portal_type=\'Software Instance\')\n
+  if software_instance:\n
+    hs = software_instance.getSpecialiseValue(\n
+                  portal_type=\'Hosting Subscription\')\n
+    if hs and hs.getSlapState() in \\\n
+        [\'start_requested\', \'stop_requested\'] and \\\n
+        not hs in hosting_subscription_list:\n
+      hosting_subscription_list.append(hs)\n
+\n
+if len(hosting_subscription_list) == 0:\n
+  return\n
+\n
+for hosting_subscription in hosting_subscription_list:\n
+  is_upgradable = hosting_subscription.HostingSubscription_isUpgradable()\n
+  if not is_upgradable:\n
+    continue\n
+  \n
+  newer_release_string = hosting_subscription.\\\n
+                    HostingSubscription_getNewerSofwareRelease()\n
+  if not newer_release_string:\n
+    continue\n
+  \n
+  software_release = portal.portal_catalog.getResultValue(\n
+                              portal_type=\'Software Release\',\n
+                              url_string=newer_release_string)\n
+  if not software_release:\n
+    continue\n
+  \n
+  title = \'A new software release is available for %s\' % \\\n
+                        hosting_subscription.getReference()\n
+  # Search if exist upgrade decision for this Hosting Subscription (by title)\n
+  is_decision_in_progress = software_release.\\\n
+          SoftwareRelease_isUpgradeDecisionInProgress(title=title)\n
+  if is_decision_in_progress:\n
+    continue\n
+\n
+  return software_release.SoftwareRelease_createUpgradeDecision(\n
+      source_url=hosting_subscription.getRelativeUrl(), title=title\n
+    )\n
+</string> </value>
+        </item>
+        <item>
+            <key> <string>_params</string> </key>
+            <value> <string></string> </value>
+        </item>
+        <item>
+            <key> <string>id</string> </key>
+            <value> <string>Computer_hostingSubscriptionCreateUpgradeDecision</string> </value>
+        </item>
+      </dictionary>
+    </pickle>
+  </record>
+</ZopeData>
diff --git a/master/bt5/slapos_pdm/SkinTemplateItem/portal_skins/slapos_pdm/SoftwareRelease_createUpgradeDecision.xml b/master/bt5/slapos_pdm/SkinTemplateItem/portal_skins/slapos_pdm/SoftwareRelease_createUpgradeDecision.xml
index 1f3d10bb4..23ddc9c5c 100644
--- a/master/bt5/slapos_pdm/SkinTemplateItem/portal_skins/slapos_pdm/SoftwareRelease_createUpgradeDecision.xml
+++ b/master/bt5/slapos_pdm/SkinTemplateItem/portal_skins/slapos_pdm/SoftwareRelease_createUpgradeDecision.xml
@@ -57,11 +57,18 @@ from DateTime import DateTime\n
 portal = context.getPortalObject()\n
 \n
 software_release = context\n
-computer = portal.restrictedTraverse(computer_url, None)\n
-if not computer:\n
+source_product = portal.restrictedTraverse(source_url, None)\n
+if not source_product:\n
+  return\n
+\n
+portal_type = source_product.getPortalType()\n
+if portal_type == \'Computer\':\n
+  person_url = source_product.getSourceAdministration()\n
+elif portal_type == \'Hosting Subscription\':\n
+  person_url = source_product.getDestinationSection()\n
+else:\n
   return\n
 \n
-person_url = computer.getSourceAdministration()\n
 if not person_url:\n
   return\n
 \n
@@ -83,9 +90,9 @@ else:\n
                     portal_type=\'Upgrade Decision Line\')\n
 \n
 decision_line.edit(\n
-  title=\'Request decision upgrade for %s on computer %s\' % (\n
-    software_release.getTitle(), computer.getReference()),\n
-  aggregate=[computer_url, software_release.getRelativeUrl()])\n
+  title=\'Request decision upgrade for %s on %s %s\' % (\n
+    software_release.getTitle(), portal_type, source_product.getReference()),\n
+  aggregate=[source_url, software_release.getRelativeUrl()])\n
 \n
 return upgrade_decision\n
 
@@ -94,7 +101,7 @@ return upgrade_decision\n
         </item>
         <item>
             <key> <string>_params</string> </key>
-            <value> <string>computer_url, title</string> </value>
+            <value> <string>source_url, title</string> </value>
         </item>
         <item>
             <key> <string>id</string> </key>
diff --git a/master/bt5/slapos_pdm/SkinTemplateItem/portal_skins/slapos_pdm/SoftwareRelease_isUpgradeDecisionInProgress.xml b/master/bt5/slapos_pdm/SkinTemplateItem/portal_skins/slapos_pdm/SoftwareRelease_isUpgradeDecisionInProgress.xml
index 1c5d8a9b6..801510fdf 100644
--- a/master/bt5/slapos_pdm/SkinTemplateItem/portal_skins/slapos_pdm/SoftwareRelease_isUpgradeDecisionInProgress.xml
+++ b/master/bt5/slapos_pdm/SkinTemplateItem/portal_skins/slapos_pdm/SoftwareRelease_isUpgradeDecisionInProgress.xml
@@ -62,9 +62,14 @@ if len(upgrade_decision_in_progress) == 0:\n
 \n
 in_progress = False\n
 for decision_in_progress in upgrade_decision_in_progress:\n
-  found_url = decision_in_progress.\\\n
-              UpgradeDecision_getSoftwareRelease().getUrlString()\n
-  if found_url == url_string:\n
+  try:\n
+    software_release = decision_in_progress.\\\n
+              UpgradeDecision_getSoftwareRelease()\n
+  except ValueError:\n
+    continue\n
+  if not software_release:\n
+    continue\n
+  if url_string == software_release.getUrlString():\n
     in_progress = True\n
     break\n
 \n
diff --git a/master/bt5/slapos_pdm/TestTemplateItem/testSlapOSPDMAlarm.py b/master/bt5/slapos_pdm/TestTemplateItem/testSlapOSPDMAlarm.py
index ba10cfd16..fbfc47f84 100644
--- a/master/bt5/slapos_pdm/TestTemplateItem/testSlapOSPDMAlarm.py
+++ b/master/bt5/slapos_pdm/TestTemplateItem/testSlapOSPDMAlarm.py
@@ -108,7 +108,8 @@ return %s
       '*args, **kw',
       '# Script body\n'
 """portal_workflow = context.portal_workflow
-portal_workflow.doActionFor(context, action='edit_action', comment='Visited by Computer_checkAndCreateUpgradeDecision') """ )
+portal_workflow.doActionFor(context, action='edit_action', comment='%s') """ % \
+      'Visited by Computer_checkAndCreateUpgradeDecision')
     transaction.commit()
 
   def _dropComputer_checkAndCreateUpgradeDecision(self):
@@ -137,4 +138,45 @@ portal_workflow.doActionFor(context, action='edit_action', comment='Visited by C
     
     self.assertNotEqual('Visited by Computer_checkAndCreateUpgradeDecision',
       computer2.workflow_history['edit_workflow'][-1]['comment'])
+  
+  def _simulateComputer_hostingSubscriptionCreateUpgradeDecision(self):
+    script_name = 'Computer_hostingSubscriptionCreateUpgradeDecision'
+    if script_name in self.portal.portal_skins.custom.objectIds():
+      raise ValueError('Precondition failed: %s exists in custom' % script_name)
+    createZODBPythonScript(self.portal.portal_skins.custom,
+      script_name,
+      '*args, **kw',
+      '# Script body\n'
+"""portal_workflow = context.portal_workflow
+portal_workflow.doActionFor(context, action='edit_action', comment='%s') """ % \
+      'Visited by Computer_hostingSubscriptionCreateUpgradeDecision')
+    transaction.commit()
 
+  def _dropComputer_hostingSubscriptionCreateUpgradeDecision(self):
+    script_name = 'Computer_hostingSubscriptionCreateUpgradeDecision'
+    if script_name in self.portal.portal_skins.custom.objectIds():
+      self.portal.portal_skins.custom.manage_delObjects(script_name)
+    transaction.commit()
+  
+  def test_Alarm_computerCheckUpgradeHostingSubscription(self):
+    computer = self._makeComputer(self.new_id)
+    computer.edit(allocation_scope = 'open/public')
+    computer2 = self._makeComputer(self.generateNewId())
+    computer2.edit(allocation_scope = 'open/personal')
+    
+    self._simulateComputer_hostingSubscriptionCreateUpgradeDecision()
+
+    try:
+      self.portal.portal_alarms.slapos_hosting_subscription_create_upgrade_decision.\
+        activeSense()
+      self.tic()
+    finally:
+      self._dropComputer_hostingSubscriptionCreateUpgradeDecision()
+
+    self.assertEqual('Visited by Computer_hostingSubscriptionCreateUpgradeDecision',
+      computer.workflow_history['edit_workflow'][-1]['comment'])
+    
+    self.assertNotEqual('Visited by Computer_hostingSubscriptionCreateUpgradeDecision',
+      computer2.workflow_history['edit_workflow'][-1]['comment'])
+      
+      
diff --git a/master/bt5/slapos_pdm/TestTemplateItem/testSlapOSPDMSkins.py b/master/bt5/slapos_pdm/TestTemplateItem/testSlapOSPDMSkins.py
index 1e60f3165..048c3e2b9 100644
--- a/master/bt5/slapos_pdm/TestTemplateItem/testSlapOSPDMSkins.py
+++ b/master/bt5/slapos_pdm/TestTemplateItem/testSlapOSPDMSkins.py
@@ -503,14 +503,14 @@ class TestSlapOSPDMSkins(testSlapOSMixin):
     self.assertEqual('stopped', upgrade_decision.getSimulationState())
 
 
-  def testSoftwareRelease_createUpgradeDecision(self):
+  def testSoftwareRelease_createUpgradeDecision_computer(self):
     person = self._makePerson(self.new_id)
     computer = self._makeComputer(self.new_id)
     computer.edit(source_administration_value=person)
     software_release = self._makeSoftwareRelease(self.new_id)
     
     upgrade_decision = software_release.SoftwareRelease_createUpgradeDecision(
-          computer_url=computer.getRelativeUrl(),
+          source_url=computer.getRelativeUrl(),
           title="TEST-SRUPDE-%s" % self.new_id)
     self.tic()
     
@@ -522,7 +522,7 @@ class TestSlapOSPDMSkins(testSlapOSMixin):
                     portal_type='Upgrade Decision Line')[0]
     
     self.assertEqual(decision_line.getTitle(),
-                        'Request decision upgrade for %s on computer %s' % (
+                        'Request decision upgrade for %s on Computer %s' % (
                         software_release.getTitle(), computer.getReference())
                     )
     self.assertEqual(decision_line.getAggregate(portal_type='Computer'),
@@ -531,6 +531,31 @@ class TestSlapOSPDMSkins(testSlapOSMixin):
                       software_release.getRelativeUrl())
   
   
+  def testSoftwareRelease_createUpgradeDecision_hostingSubscription(self):
+    person = self._makePerson(self.new_id)
+    hosting_subscription = self._makeHostingSubscription(self.new_id)
+    hosting_subscription.edit(
+          destination_section_value = person.getRelativeUrl())
+    software_release = self._makeSoftwareRelease(self.new_id)
+    
+    upgrade_decision = software_release.SoftwareRelease_createUpgradeDecision(
+          source_url=hosting_subscription.getRelativeUrl(),
+          title="TEST-SRUPDE-%s" % self.new_id)
+    self.tic()
+    
+    self.assertEqual(upgrade_decision.getSimulationState(), 'confirmed')
+    self.assertEqual(upgrade_decision.getDestinationSection(),
+                       person.getRelativeUrl())
+    
+    decision_line = upgrade_decision.contentValues(
+                    portal_type='Upgrade Decision Line')[0]
+                    
+    self.assertEqual(decision_line.getAggregate(portal_type='Hosting Subscription'),
+                      hosting_subscription.getRelativeUrl())
+    self.assertEqual(decision_line.getAggregate(portal_type='Software Release'),
+                      software_release.getRelativeUrl())
+  
+  
   def testSoftwareRelease_isUpgradeDecisionInProgress(self):
     computer = self._makeComputer(self.new_id)
     software_release = self._makeSoftwareRelease(self.new_id)
@@ -586,7 +611,6 @@ class TestSlapOSPDMSkins(testSlapOSMixin):
     
     upgrade_decision = computer.Computer_checkAndCreateUpgradeDecision()
     
-    self.assertNotEqual(upgrade_decision, None)
     self.assertEqual(upgrade_decision.getSimulationState(), 'confirmed')
     
     computer_aggregate = upgrade_decision.UpgradeDecision_getComputer()
@@ -600,5 +624,79 @@ class TestSlapOSPDMSkins(testSlapOSMixin):
     upgrade_decision2 = computer.Computer_checkAndCreateUpgradeDecision()
     
     self.assertEqual(upgrade_decision2, None)
+  
+  
+  def testComputer_hostingSubscriptionCreateUpgradeDecision_no_newer(self):
+    person = self._makePerson(self.new_id)
+    computer = self._makeComputer(self.new_id)
+    computer.edit(source_administration_value=person)
+    self._makeComputerPartitions(computer)
+    software_product = self._makeSoftwareProduct(self.new_id)
+    software_release = self._requestSoftwareRelease(self.new_id,
+                                    software_product.getRelativeUrl())
+    url_string = software_release.getUrlString()
+    self._makeSoftwareInstallation(self.new_id, computer, url_string)
+    self.tic()
+    
+    upgrade_decision = computer.Computer_hostingSubscriptionCreateUpgradeDecision()
+    self.assertEqual(upgrade_decision, None)
+    
+    # Create Hosting Subscription
+    hosting_subscription = self._makeFullHostingSubscription(self.new_id,
+                                    url_string, person)
+    self.tic()
+    
+    upgrade_decision = computer.Computer_hostingSubscriptionCreateUpgradeDecision()
+    self.assertEqual(upgrade_decision, None)
+    
+    self._makeFullSoftwareInstance(hosting_subscription, url_string)
+    self._markComputerPartitionBusy(computer,
+                                    hosting_subscription.getPredecessorValue())
+    
+    self._requestSoftwareRelease(self.generateNewId(),
+                                    software_product.getRelativeUrl())
+    self.tic()
+    
+    upgrade_decision = computer.Computer_hostingSubscriptionCreateUpgradeDecision()
+    self.assertEqual(upgrade_decision, None)
+  
+  def testComputer_hostingSubscriptionCreateUpgradeDecision(self):
+    person = self._makePerson(self.new_id)
+    computer = self._makeComputer(self.new_id)
+    computer.edit(source_administration_value=person)
+    self._makeComputerPartitions(computer)
+    software_product = self._makeSoftwareProduct(self.new_id)
+    software_release = self._requestSoftwareRelease(self.new_id,
+                                    software_product.getRelativeUrl())
+    url_string = software_release.getUrlString()
+    
+    self._makeSoftwareInstallation(self.new_id, computer, url_string)
+    
+    # Create Hosting Subscription and Software Instance
+    hosting_subscription = self._makeFullHostingSubscription(self.new_id,
+                                    url_string, person)
+    self._makeFullSoftwareInstance(hosting_subscription, url_string)
+    self._markComputerPartitionBusy(computer,
+                                    hosting_subscription.getPredecessorValue())
+    
+    # Install the Newest software release
+    software_release2 = self._requestSoftwareRelease(self.generateNewId(),
+                                      software_product.getRelativeUrl())
+    self._makeSoftwareInstallation(self.new_id, computer,
+                                    software_release2.getUrlString())
+    self.tic()
+    
+    upgrade_decision = computer.Computer_hostingSubscriptionCreateUpgradeDecision()
+    self.assertEqual(upgrade_decision.getSimulationState(), 'confirmed')
+    
+    self.assertEqual(upgrade_decision.UpgradeDecision_getHostingSubscription().\
+                      getReference(), hosting_subscription.getReference())
+
+    self.assertEqual(upgrade_decision.UpgradeDecision_getSoftwareRelease().\
+                              getUrlString(), software_release2.getUrlString())
+    
+    self.tic()
+    upgrade_decision2 = computer.Computer_hostingSubscriptionCreateUpgradeDecision()
+    self.assertEqual(upgrade_decision2, None)
     
     
\ No newline at end of file
diff --git a/master/bt5/slapos_pdm/bt/revision b/master/bt5/slapos_pdm/bt/revision
index 19c7bdba7..8e2afd342 100644
--- a/master/bt5/slapos_pdm/bt/revision
+++ b/master/bt5/slapos_pdm/bt/revision
@@ -1 +1 @@
-16
\ No newline at end of file
+17
\ No newline at end of file
diff --git a/master/bt5/slapos_pdm/bt/template_path_list b/master/bt5/slapos_pdm/bt/template_path_list
index 5b5e14eed..47799bdc0 100644
--- a/master/bt5/slapos_pdm/bt/template_path_list
+++ b/master/bt5/slapos_pdm/bt/template_path_list
@@ -1,3 +1,4 @@
+portal_alarms/slapos_hosting_subscription_create_upgrade_decision
 portal_alarms/slapos_manage_software_catalog
 portal_alarms/slapos_pdm_computer_create_upgrade_decision
 portal_alarms/slapos_upgrade_decision_process
-- 
2.30.9