text: 
  import logging
  
  import pytest
  from test_helpers import get_expanded_config
  
  __maintainer__ = 'branden'
  __contact__ = 'orchestration-team@mesosphere.io'
  
  log = logging.getLogger(__name__)
  
  
  def test_pkgpanda_api(dcos_api_session):
  
      expanded_config = get_expanded_config()
      if 'advanced' in expanded_config['template_filenames']:
          reason = (
              'Will not work on advanced CF templates, see: '
              'https://jira.mesosphere.com/browse/DCOS_OSS-1375'
          )
          pytest.skip(reason)
  
      def get_and_validate_package_ids(path, node):
          r = dcos_api_session.get(path, node=node)
          assert r.status_code == 200
          package_ids = r.json()
          assert isinstance(package_ids, list)
          for package_id in package_ids:
              r = dcos_api_session.get(path + package_id, node=node)
              assert r.status_code == 200
              name, version = package_id.split('--')
              assert r.json() == {'id': package_id, 'name': name, 'version': version}
          return package_ids
  
      active_buildinfo = dcos_api_session.get('/pkgpanda/active.buildinfo.full.json').json()
      active_buildinfo_packages = sorted(
          # Setup packages don't have a buildinfo.
          (package_name, info['package_version'] if info else None)
          for package_name, info in active_buildinfo.items()
      )
  
      def assert_packages_match_active_buildinfo(package_ids):
          packages = sorted(map(lambda id_: tuple(id_.split('--')), package_ids))
          assert len(packages) == len(active_buildinfo_packages)
          for package, buildinfo_package in zip(packages, active_buildinfo_packages):
              if buildinfo_package[1] is None:
                  # No buildinfo for this package, so we can only compare names.
                  assert package[0] == buildinfo_package[0]
              else:
                  assert package == buildinfo_package
  
      for node in dcos_api_session.masters + dcos_api_session.all_slaves:
          package_ids = get_and_validate_package_ids('/pkgpanda/repository/', node)
          active_package_ids = get_and_validate_package_ids('/pkgpanda/active/', node)
  
          assert set(active_package_ids) <= set(package_ids)
          assert_packages_match_active_buildinfo(active_package_ids)
  
  
  # There is no standardized way of getting package requirements from the package description json,
  # e.g. nodes could be called 'brokers' or 'nodes' or something else. This was created by looking at
  # https://github.com/mesosphere/universe/blob/version-3.x/repo/packages/N/nginx/6/config.json
  # Nginx package version 1.10.3
  NGINX_PACKAGE_REQUIREMENTS = {
      'number_of_nodes': 1,
      'node': {
          'cpus': 1,
          'mem': 1024
      }
  }
  
  
  def _get_cluster_resources(dcos_api_session):
      """Return the mesos state summary
      """
      r = dcos_api_session.get('/mesos/state-summary')
      return r.json()
  
  
  def _agent_has_resources(agent, node_requirements):
      """Check that an agent has at least as much resources as requried for one node
  
      Args:
          agent: dict Info for one 'slave' from the mesos state summary
          node_requirements: dict Resource requirements per agent
      """
      unreserved = agent['unreserved_resources']
      resources = ['mem', 'cpus']
      for resource in resources:
          log.debug('{resource}: unreserved {unreserved}, required {required}'.format(
              resource=resource,
              unreserved=unreserved[resource],
              required=node_requirements[resource]))
          if unreserved[resource] < node_requirements[resource]:
              log.debug('Agent does not have has enough {}'.format(resource))
              return False
      return True
  
  
  def _enough_resources_for_package(state_summary, package_requirements):
      """Sanity check that there are enough unreserved_resources in a state to run a package.
  
      Args:
          state_summary: dict
          package_requirements: dict
  
      Returns:
          bool
  
      Notes:
          This is a sanity check meant for use with pytest.mark.skipif
          This only verifies that there were enough resources at the time state_summary was queried
      """
      agents = state_summary['slaves']
      if len(agents) < package_requirements['number_of_nodes']:
          log.debug('Not enough agents for this package. Need {required}, have {available}'.format(
              required=package_requirements['number_of_nodes'],
              available=len(agents)))
          return False
      usable_nodes = 0
      for agent in agents:
          if _agent_has_resources(agent, package_requirements['node']):
              usable_nodes += 1
          if usable_nodes == package_requirements['number_of_nodes']:
              return True
      log.info('Only {available} usable agents. This package needs {required} with these resources {resources}.'.format(
          available=usable_nodes,
          required=package_requirements['number_of_nodes'],
          resources=package_requirements['node']))
      return False
  
  
  def _skipif_insufficient_resources(dcos_api_session, requirements):
      """Can't access dcos_api_session from through the pytest.mark.skipif decorator, so call this in each test instead
      """
      if not _enough_resources_for_package(_get_cluster_resources(dcos_api_session), requirements):
          pytest.skip(msg='Package installation would fail on this cluster due to insufficient resources')
  
  
  def test_packaging_api(dcos_api_session):
      """
      Test the Cosmos API (/package) wrapper by installing nginx from
      https://github.com/mesosphere/universe/blob/version-3.x/repo/packages/N/nginx/6
      The default configuration of ngnix needs only one agent and no service secrets are
      required even when running in a strict cluster.
      """
      _skipif_insufficient_resources(dcos_api_session, NGINX_PACKAGE_REQUIREMENTS)
      install_response = dcos_api_session.cosmos.install_package('nginx', package_version='1.10.3')
      data = install_response.json()
  
      dcos_api_session.marathon.wait_for_deployments_complete()
  
      list_response = dcos_api_session.cosmos.list_packages()
      packages = list_response.json()['packages']
      assert len(packages) == 1 and packages[0]['appId'] == data['appId']
  
      dcos_api_session.cosmos.uninstall_package('nginx', app_id=data['appId'])
  
      list_response = dcos_api_session.cosmos.list_packages()
      packages = list_response.json()['packages']
      assert len(packages) == 0
  
  
  def test_mom_installation(dcos_api_session):
      """Test the Cosmos installation of marathon on marathon (MoM)
      """
      expanded_config = get_expanded_config()
      if expanded_config.get('security') == 'strict':
          pytest.skip('MoM disabled for strict mode')
  
      install_response = dcos_api_session.cosmos.install_package('marathon')
      data = install_response.json()
  
      dcos_api_session.marathon.wait_for_deployments_complete()
  
      list_response = dcos_api_session.cosmos.list_packages()
      packages = list_response.json()['packages']
      assert len(packages) == 1 and packages[0]['appId'] == data['appId']
  
      dcos_api_session.cosmos.uninstall_package('marathon', app_id=data['appId'])
  
      list_response = dcos_api_session.cosmos.list_packages()
      packages = list_response.json()['packages']
      assert len(packages) == 0
  