text: # Copyright (c) 2015 Mirantis, Inc.
  #
  # Licensed under the Apache License, Version 2.0 (the "License"); you may
  # not use this file except in compliance with the License. You may obtain
  # a copy of the License at
  #
  # http://www.apache.org/licenses/LICENSE-2.0
  #
  # Unless required by applicable law or agreed to in writing, software
  # distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
  # WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
  # License for the specific language governing permissions and limitations
  # under the License.
  
  import os
  
  import mock
  import pkg_resources
  
  from glance.common import exception
  from glance.common.glare import loader
  from glance.contrib.plugins.artifacts_sample.v1 import artifact as art1
  from glance.contrib.plugins.artifacts_sample.v2 import artifact as art2
  from glance.tests import utils
  
  
  class MyArtifactDuplicate(art1.MyArtifact):
      __type_version__ = '1.0.1'
      __type_name__ = 'MyArtifact'
  
  
  class MyArtifactOk(art1.MyArtifact):
      __type_version__ = '1.0.2'
      __type_name__ = 'MyArtifact'
  
  
  class TestArtifactsLoader(utils.BaseTestCase):
      def setUp(self):
          self.path = 'glance.contrib.plugins.artifacts_sample'
          self._setup_loader(['MyArtifact=%s.v1.artifact:MyArtifact' %
                              self.path])
          super(TestArtifactsLoader, self).setUp()
  
      def _setup_loader(self, artifacts):
          self.loader = None
          mock_this = 'stevedore.extension.ExtensionManager._find_entry_points'
          with mock.patch(mock_this) as fep:
              fep.return_value = [
                  pkg_resources.EntryPoint.parse(art) for art in artifacts]
              self.loader = loader.ArtifactsPluginLoader(
                  'glance.artifacts.types')
  
      def test_load(self):
          """
          Plugins can be loaded as entrypoint=single plugin and
          entrypoint=[a, list, of, plugins]
          """
          # single version
          self.assertEqual(1, len(self.loader.mgr.extensions))
          self.assertEqual(art1.MyArtifact,
                           self.loader.get_class_by_endpoint('myartifact'))
          # entrypoint = [a, list]
          path = os.path.splitext(__file__)[0][__file__.rfind(
              'glance'):].replace('/', '.')
          self._setup_loader([
              'MyArtifact=%s:MyArtifactOk' % path,
              'MyArtifact=%s.v2.artifact:MyArtifact' % self.path,
              'MyArtifact=%s.v1.artifact:MyArtifact' % self.path]),
          self.assertEqual(3, len(self.loader.mgr.extensions))
          # returns the plugin with the latest version
          self.assertEqual(art2.MyArtifact,
                           self.loader.get_class_by_endpoint('myartifact'))
          self.assertEqual(art1.MyArtifact,
                           self.loader.get_class_by_endpoint('myartifact',
                                                             '1.0.1'))
  
      def test_basic_loader_func(self):
          """Test public methods of PluginLoader class here"""
          # type_version 2 == 2.0 == 2.0.0
          self._setup_loader(
              ['MyArtifact=%s.v2.artifact:MyArtifact' % self.path])
          self.assertEqual(art2.MyArtifact,
                           self.loader.get_class_by_endpoint('myartifact'))
          self.assertEqual(art2.MyArtifact,
                           self.loader.get_class_by_endpoint('myartifact',
                                                             '2.0'))
          self.assertEqual(art2.MyArtifact,
                           self.loader.get_class_by_endpoint('myartifact',
                                                             '2.0.0'))
          self.assertEqual(art2.MyArtifact,
                           self.loader.get_class_by_endpoint('myartifact',
                                                             '2'))
          # now make sure that get_class_by_typename works as well
          self.assertEqual(art2.MyArtifact,
                           self.loader.get_class_by_typename('MyArtifact'))
          self.assertEqual(art2.MyArtifact,
                           self.loader.get_class_by_typename('MyArtifact', '2'))
  
      def test_config_validation(self):
          """
          Plugins can be loaded on certain conditions:
              * entry point name == type_name
              * no plugin with the same type_name and version has been already
                loaded
          """
          path = 'glance.contrib.plugins.artifacts_sample'
          # here artifacts specific validation is checked
          self.assertRaises(exception.ArtifactNonMatchingTypeName,
                            self._setup_loader,
                            ['non_matching_name=%s.v1.artifact:MyArtifact' %
                             path])
          # make sure this call is ok
          self._setup_loader(['MyArtifact=%s.v1.artifact:MyArtifact' % path])
          art_type = self.loader.get_class_by_endpoint('myartifact')
          self.assertEqual('MyArtifact', art_type.metadata.type_name)
          self.assertEqual('1.0.1', art_type.metadata.type_version)
          # now try to add duplicate artifact with the same type_name and
          # type_version as already exists
          bad_art_path = os.path.splitext(__file__)[0][__file__.rfind(
              'glance'):].replace('/', '.')
          self.assertEqual(art_type.metadata.type_version,
                           MyArtifactDuplicate.metadata.type_version)
          self.assertEqual(art_type.metadata.type_name,
                           MyArtifactDuplicate.metadata.type_name)
          # should raise an exception as (name, version) is not unique
          self.assertRaises(
              exception.ArtifactDuplicateNameTypeVersion, self._setup_loader,
              ['MyArtifact=%s.v1.artifact:MyArtifact' % path,
               'MyArtifact=%s:MyArtifactDuplicate' % bad_art_path])
          # two artifacts with the same name but different versions coexist fine
          self.assertEqual('MyArtifact', MyArtifactOk.metadata.type_name)
          self.assertNotEqual(art_type.metadata.type_version,
                              MyArtifactOk.metadata.type_version)
          self._setup_loader(['MyArtifact=%s.v1.artifact:MyArtifact' % path,
                              'MyArtifact=%s:MyArtifactOk' % bad_art_path])
  
      def test_check_function(self):
          """
          A test to show that plugin-load specific options in artifacts.conf
          are correctly processed:
  
          * no plugins can be loaded if load_enabled = False
          * if available_plugins list is given only plugins specified can be
            be loaded
  
          """
          self.config(load_enabled=False)
          self.assertRaises(exception.ArtifactLoadError,
                            self._setup_loader,
                            ['MyArtifact=%s.v1.artifact:MyArtifact' % self.path])
          self.config(load_enabled=True, available_plugins=['MyArtifact-1.0.2'])
          self.assertRaises(exception.ArtifactLoadError,
                            self._setup_loader,
                            ['MyArtifact=%s.v1.artifact:MyArtifact' % self.path])
          path = os.path.splitext(__file__)[0][__file__.rfind(
              'glance'):].replace('/', '.')
          self._setup_loader(['MyArtifact=%s:MyArtifactOk' % path])
          # make sure that plugin_map has the expected plugin
          self.assertEqual(MyArtifactOk,
                           self.loader.get_class_by_endpoint('myartifact',
                                                             '1.0.2'))
  