[PATCH 11 of 11 saem_ref] [ark] Use random ARK identifier generator everywhere

Denis Laxalde denis.laxalde at logilab.fr
Mon Feb 12 15:20:47 CET 2018


# HG changeset patch
# User Denis Laxalde <denis.laxalde at logilab.fr>
# Date 1518441127 -3600
#      Mon Feb 12 14:12:07 2018 +0100
# Node ID a66ab0187b69278c74957d545d70e7432eda20ee
# Parent  b7e9f5f19a5093cc4c798fed2a84744f9ce95ee2
# Available At http://hg.logilab.org/review/cubes/saem_ref
#              hg pull http://hg.logilab.org/review/cubes/saem_ref -r a66ab0187b69
# EXP-Topic ark/postgres-generated
[ark] Use random ARK identifier generator everywhere

We only keep one IARKGenerator adapter as there is now only one way to
generate ARK identifier independently of which entity type it is for or
whether it is for internal or external purposes.

In testutils.py, we introduce a couple of helper function to check ARK
identifiers (or part of them) in tests.

Important changes in tests are:

* test_views.py: we now check that an entity exist from specified
  attribute (from user input) and generated ARK in a
  _check_entity_from_path() helper method (we sometimes added an
  attribute in form to disambiguate the create entity more easily);

* unittest_entities.py: we only keep one test and there isn't a
  distinction between internal and external identifiers anymore;

Related to extranet #46881387.

diff --git a/cubicweb_saem_ref/entities/__init__.py b/cubicweb_saem_ref/entities/__init__.py
--- a/cubicweb_saem_ref/entities/__init__.py
+++ b/cubicweb_saem_ref/entities/__init__.py
@@ -27,13 +27,8 @@ ARK_CONTROLCHAR = 'g'
 ARK_NAME_LENGTH = 10
 
 
-def make_ark(name):
-    return u'rf{name}g'.format(name=name)
-
-
-class ARKGeneratorMixIn(object):
-    """Entity adapter for ARK unique identifier generation"""
-    __abstract__ = True
+class ARKIdentifierGenerator(Adapter):
+    """Adapter for ARK unique identifier generation"""
     __regid__ = 'IARKGenerator'
     __select__ = match_kwargs('naa_what')
 
@@ -43,14 +38,6 @@ class ARKGeneratorMixIn(object):
 
     def assign_name(self):
         """Assign and return a new name part of the ARK identifier"""
-        raise NotImplementedError()
-
-
-class ARKExtIdentifierGenerator(ARKGeneratorMixIn, Adapter):
-    """Simple adapter for allocation of ark to object which are not (yet) entities."""
-
-    def assign_name(self):
-        """Return a new unique identifier as unicode"""
         cu = self._cw.system_sql(
             'select * from gen_ark(%s, %s, %s);',
             (ARK_NAME_LENGTH, ARK_PREFIX, ARK_CONTROLCHAR),
@@ -59,17 +46,6 @@ class ARKExtIdentifierGenerator(ARKGener
         return ark_name
 
 
-class ARKCWIdentifierGenerator(ARKGeneratorMixIn, Adapter):
-    """saem_ref.IARKGenerator entity adapter generating ARK like identifier during non-production
-    phase.
-    """
-    __select__ = ARKGeneratorMixIn.__select__ & match_kwargs('eid')
-
-    def assign_name(self):
-        eid = self.cw_extra_kwargs['eid']
-        return make_ark(u'{0:09d}'.format(eid))
-
-
 class ArkNAALocator(EntityAdapter):
     """Adapter responsible to retrieve the proper ARK Name Assigning Authority depending on the
     entity type
diff --git a/cubicweb_saem_ref/hooks.py b/cubicweb_saem_ref/hooks.py
--- a/cubicweb_saem_ref/hooks.py
+++ b/cubicweb_saem_ref/hooks.py
@@ -222,7 +222,7 @@ def set_ark_and_cwuri(cw, eid, entity_at
                 msg = _('an ARK identifier has to be generated but no Name Assigning Authority is '
                         'specified')
                 raise ValidationError(None, {None: msg})
-            generator = cw.vreg['adapters'].select('IARKGenerator', cw, eid=eid,
+            generator = cw.vreg['adapters'].select('IARKGenerator', cw,
                                                    naa_what=naa_what)
             ark = generator.generate_ark()
         entity_attrs['ark'] = ark
diff --git a/test/test_ccplugin.py b/test/test_ccplugin.py
--- a/test/test_ccplugin.py
+++ b/test/test_ccplugin.py
@@ -75,7 +75,7 @@ class ImportEacDataCommandTC(CCPluginTC)
         with self.admin_access.repo_cnx() as cnx:
             record = cnx.find('AuthorityRecord').one()
             self.assertEqual(record.dc_title(), u"Centre d'information et d'orientation (CIO)")
-            self.assertTrue(record.ark.startswith('0/rf0'), record.ark)
+            self.assertTrue(testutils.match_ark(record.ark), record.ark)
 
     def test_bad_authority(self):
         code, output = self.run_import_eac('--authority', 'unexisting')
diff --git a/test/test_seda.py b/test/test_seda.py
--- a/test/test_seda.py
+++ b/test/test_seda.py
@@ -130,11 +130,11 @@ class CloneImportTC(CubicWebTC):
         with self.admin_access.web_request(**params) as req:
             path, _ = self.expect_redirect_handle_request(
                 req, 'seda.doimport')
-            match = re.match(r'^ark:/0/rf0*(\d+)g$', path)
+            match = re.match(r'^ark:/(0/rf.{7}g)$', path)
             assert match, path
-            eid = int(match.group(1))
-            rset = req.execute('Any X WHERE X seda_archive_unit P, P eid %(p)s',
-                               {'p': eid})
+            ark = match.group(1)
+            rset = req.execute('Any X WHERE X seda_archive_unit P, P ark %(ark)s',
+                               {'ark': ark})
             self.assertTrue(rset)
 
 
diff --git a/test/test_views.py b/test/test_views.py
--- a/test/test_views.py
+++ b/test/test_views.py
@@ -315,6 +315,14 @@ class ArkViewsTC(CubicWebTC):
 
     configcls = PostgresApptestConfiguration
 
+    def _check_entity_from_path(self, cnx, path, etype, **kwargs):
+        """Make sure an entity with `etype` and `kwargs` attributes values
+        exists and matches ARK identifier found in `path`.
+        """
+        entity = cnx.find(etype, **kwargs).one()
+        self.assertTrue(path.startswith('ark:/'), path)
+        self.assertEqual(entity.ark, path[len('ark:/'):])
+
     def test_ark_authority_record_creation(self):
         with self.admin_access.cnx() as cnx:
             org = testutils.authority_with_naa(cnx)
@@ -325,6 +333,7 @@ class ArkViewsTC(CubicWebTC):
             record = self.vreg['etypes'].etype_class('AuthorityRecord')(req)
             record.eid = 'A'
             fields = {
+                role_name('record_id', 'subject'): u'test',
                 role_name('ark', 'subject'): u'',
                 role_name('agent_kind', 'subject'): str(akind.eid),
                 role_name('ark_naa', 'subject'): str(naa_eid),
@@ -338,9 +347,8 @@ class ArkViewsTC(CubicWebTC):
             req.form = self.fake_form('edition', entity_field_dicts=[(record, fields),
                                                                      (name, name_fields)])
             path = self.expect_redirect_handle_request(req)[0]
-            eid = eid_from_ark(path)
-            record = req.cnx.entity_from_eid(eid)
-            self.assertEqual(record.ark, u'0/rf%09dg' % eid)
+            self._check_entity_from_path(req, path, 'AuthorityRecord',
+                                         record_id=u'test')
 
     def test_ark_agent_creation(self):
         with self.admin_access.web_request() as req:
@@ -352,21 +360,20 @@ class ArkViewsTC(CubicWebTC):
                       role_name('authority', 'subject'): str(org.eid)}
             req.form = self.fake_form('edition', entity_field_dicts=[(agent, fields)])
             path = self.expect_redirect_handle_request(req)[0]
-            eid = eid_from_ark(path)
-            agent = req.cnx.entity_from_eid(eid)
-            self.assertEqual(agent.ark, u'0/rf%09dg' % eid)
+            self._check_entity_from_path(req, path, 'Agent',
+                                         name=u'007')
 
     def test_ark_scheme_creation(self):
         with self.admin_access.web_request() as req:
             scheme = self.vreg['etypes'].etype_class('ConceptScheme')(req)
             scheme.eid = 'A'
-            fields = {role_name('ark', 'subject'): u'',
+            fields = {role_name('title', 'subject'): u'test',
+                      role_name('ark', 'subject'): u'',
                       role_name('ark_naa', 'subject'): text_type(testutils.naa(req.cnx).eid)}
             req.form = self.fake_form('edition', entity_field_dicts=[(scheme, fields)])
             path = self.expect_redirect_handle_request(req)[0]
-            eid = eid_from_ark(path)
-            scheme = req.cnx.entity_from_eid(eid)
-            self.assertEqual(scheme.ark, u'0/rf%09dg' % eid)
+            self._check_entity_from_path(req, path, 'ConceptScheme',
+                                         title=u'test')
 
     def test_ark_concept_creation_form(self):
         # test addition of a concept by specifying in_scheme in form
@@ -375,6 +382,7 @@ class ArkViewsTC(CubicWebTC):
             concept = self.vreg['etypes'].etype_class('Concept')(req)
             concept.eid = 'A'
             concept_fields = {role_name('in_scheme', 'subject'): str(scheme.eid),
+                              role_name('definition', 'subject'): u'thing',
                               role_name('ark', 'subject'): u''}
             label = self.vreg['etypes'].etype_class('Label')(req)
             label.eid = 'B'
@@ -383,9 +391,8 @@ class ArkViewsTC(CubicWebTC):
             req.form = self.fake_form('edition', entity_field_dicts=[(concept, concept_fields),
                                                                      (label, label_fields)])
             path = self.expect_redirect_handle_request(req)[0]
-            eid = eid_from_ark(path)
-            concept = req.cnx.entity_from_eid(eid)
-            self.assertEqual(concept.ark, u'0/rf%09dg' % eid)
+            self._check_entity_from_path(req, path, 'Concept',
+                                         definition=u'thing')
 
     def test_ark_concept_creation_linkto(self):
         # test addition of a concept by specifying in_scheme with __linkto
@@ -393,7 +400,9 @@ class ArkViewsTC(CubicWebTC):
             scheme = req.cnx.create_entity('ConceptScheme', ark_naa=testutils.naa(req.cnx))
             concept = self.vreg['etypes'].etype_class('Concept')(req)
             concept.eid = 'A'
-            concept_fields = {}
+            concept_fields = {
+                role_name('definition', 'subject'): u'thing',
+            }
             label = self.vreg['etypes'].etype_class('Label')(req)
             label.eid = 'B'
             label_fields = {role_name('label', 'subject'): u'Goodby',
@@ -402,9 +411,8 @@ class ArkViewsTC(CubicWebTC):
                                                                      (label, label_fields)])
             req.form['__linkto'] = 'in_scheme:%s:subject' % scheme.eid
             path = self.expect_redirect_handle_request(req)[0]
-            eid = eid_from_ark(path)
-            concept = req.cnx.entity_from_eid(eid)
-            self.assertEqual(concept.ark, u'0/rf%09dg' % eid)
+            self._check_entity_from_path(req, path, 'Concept',
+                                         definition=u'thing')
 
     def test_ark_url_rewrite(self):
         with self.admin_access.web_request() as req:
@@ -485,7 +493,7 @@ class AssignArkWebServiceTC(CubicWebTC):
             json_response = json.loads(result)
             self.assertIn('ark', json_response[0])
             ark = json_response[0]['ark']
-            self.assertTrue(testutils.match_ark(ark), ark)
+            self.assertTrue(testutils.ARK_RGX.match(ark), ark)
 
         params = {'organization': org_ark}
         with self.admin_access.web_request(
diff --git a/test/testutils.py b/test/testutils.py
--- a/test/testutils.py
+++ b/test/testutils.py
@@ -122,6 +122,14 @@ def authority_with_naa(cnx, name=u'Defau
     return authority
 
 
+ARK_URI_RGX = re.compile(
+    r'^ark:/0/%s.{%d}%s$'
+    % (ARK_PREFIX,
+       ARK_NAME_LENGTH - len(ARK_PREFIX) - len(ARK_CONTROLCHAR),
+       ARK_CONTROLCHAR),
+)
+
+
 ARK_RGX = re.compile(
     r'^0/%s.{%d}%s$'
     % (ARK_PREFIX,
@@ -130,10 +138,26 @@ ARK_RGX = re.compile(
 )
 
 
+ARK_NAME_RGX = re.compile(
+    r'^%s.{%d}%s$'
+    % (ARK_PREFIX,
+       ARK_NAME_LENGTH - len(ARK_PREFIX) - len(ARK_CONTROLCHAR),
+       ARK_CONTROLCHAR),
+)
+
+
+def match_ark_uri(text):
+    return ARK_URI_RGX.match(text)
+
+
 def match_ark(text):
     return ARK_RGX.match(text)
 
 
+def match_ark_name(text):
+    return ARK_NAME_RGX.match(text)
+
+
 def setup_scheme(cnx, title, *labels, **kwargs):
     """Return info new concept scheme"""
     scheme = cnx.create_entity('ConceptScheme', title=title, ark_naa=naa(cnx), **kwargs)
diff --git a/test/unittest_entities.py b/test/unittest_entities.py
--- a/test/unittest_entities.py
+++ b/test/unittest_entities.py
@@ -28,21 +28,15 @@ class ArkGeneratorTC(CubicWebTC):
 
     configcls = PostgresApptestConfiguration
 
-    def assertIsArk(self, text):
-        self.assertRegexpMatches(text, r'^saemref-test/rf.{7}g$')
-
-    def test_eid(self):
+    def test(self):
+        what = 'saemref-test'
         with self.admin_access.repo_cnx() as cnx:
             generator = self.vreg['adapters'].select(
-                'IARKGenerator', cnx, eid=42, naa_what='saemref-test')
-            self.assertEqual(generator.generate_ark(),
-                             'saemref-test/rf000000042g')
-
-    def test_ext_identifier(self):
-        with self.admin_access.repo_cnx() as cnx:
-            generator = self.vreg['adapters'].select('IARKGenerator', cnx,
-                                                     naa_what='saemref-test')
-            self.assertIsArk(generator.generate_ark())
+                'IARKGenerator', cnx, naa_what=what)
+            ark = generator.generate_ark()
+        self.assertTrue(ark.startswith(what + '/'), ark)
+        name = ark[len(what) + 1:]
+        self.assertTrue(testutils.match_ark_name(name), name)
 
 
 if __name__ == '__main__':
diff --git a/test/unittest_hooks.py b/test/unittest_hooks.py
--- a/test/unittest_hooks.py
+++ b/test/unittest_hooks.py
@@ -209,26 +209,31 @@ class SAEMRefHooksTC(CubicWebTC):
             self.assertEqual(arelation.association_from[0], alice)
             self.failIf(cnx.execute('Any X WHERE X eid %(x)s', {'x': exturi.eid}))
 
+    def _check_ark(self, entity):
+        self.assertTrue(testutils.match_ark(entity.ark), entity.ark)
+
+    def _check_ark_and_cwuri(self, entity):
+        self._check_ark(entity)
+        self.assertTrue(testutils.match_ark_uri(entity.cwuri), entity.cwuri)
+
     def test_ark_generation_authorityrecord(self):
         with self.admin_access.repo_cnx() as cnx:
             agent = testutils.authority_record(cnx, u'bob')
             cnx.commit()
-            self.assertEqual(agent.ark, '0/rf%09dg' % agent.eid)
-            self.assertEqual(agent.cwuri, 'ark:/0/rf%09dg' % agent.eid)
+            self._check_ark_and_cwuri(agent)
             agent = testutils.authority_record(cnx, u'john', ark=u'authority/123456')
             cnx.commit()
             self.assertEqual(agent.ark, 'authority/123456')
             self.assertEqual(agent.cwuri, 'ark:/authority/123456')
             agent = testutils.authority_record(cnx, u'alf', cwuri=u'http://someuri/someagent')
             cnx.commit()
-            self.assertEqual(agent.ark, '0/rf%09dg' % agent.eid)
+            self._check_ark(agent)
             self.assertEqual(agent.cwuri, 'http://someuri/someagent')
 
     def test_ark_generation_seda_profile(self):
         with self.admin_access.repo_cnx() as cnx:
             profile = testutils.setup_profile(cnx)
-            self.assertEqual(profile.ark, '0/rf{0:09d}g'.format(profile.eid))
-            self.assertEqual(profile.cwuri, 'ark:/0/rf{0:09d}g'.format(profile.eid))
+            self._check_ark_and_cwuri(profile)
 
     def test_ark_generation_seda_profile_ark_given(self):
         with self.admin_access.repo_cnx() as cnx:
@@ -240,7 +245,7 @@ class SAEMRefHooksTC(CubicWebTC):
         with self.admin_access.repo_cnx() as cnx:
             profile = testutils.setup_profile(
                 cnx, cwuri=u'http://example.org/profile/125')
-            self.assertEqual(profile.ark, '0/rf{0:09d}g'.format(profile.eid))
+            self._check_ark(profile)
             self.assertEqual(profile.cwuri, 'http://example.org/profile/125')
 
     def test_ark_generation_concept(self):
@@ -248,19 +253,15 @@ class SAEMRefHooksTC(CubicWebTC):
             scheme = cnx.create_entity('ConceptScheme', ark_naa=testutils.naa(cnx))
             concept = scheme.add_concept(u'some object')
             cnx.commit()
-            self.assertEqual(scheme.ark, '0/rf%09dg' % scheme.eid)
-            self.assertEqual(scheme.cwuri,
-                             'ark:/0/rf%09dg' % scheme.eid)
-            self.assertEqual(concept.ark, '0/rf%09dg' % concept.eid)
-            self.assertEqual(concept.cwuri,
-                             'ark:/0/rf%09dg' % concept.eid)
+            self._check_ark_and_cwuri(scheme)
+            self._check_ark_and_cwuri(concept)
             scheme = cnx.create_entity('ConceptScheme', cwuri=u'http://someuri/somescheme',
                                        ark_naa=testutils.naa(cnx))
             concept = scheme.add_concept(u'some object', cwuri=u'http://someuri/someconcept')
             cnx.commit()
-            self.assertEqual(scheme.ark, '0/rf%09dg' % scheme.eid)
+            self._check_ark(scheme)
             self.assertEqual(scheme.cwuri, 'http://someuri/somescheme')
-            self.assertEqual(concept.ark, '0/rf%09dg' % concept.eid)
+            self._check_ark(concept)
             self.assertEqual(concept.cwuri, 'http://someuri/someconcept')
             scheme = cnx.create_entity('ConceptScheme', cwuri=u'http://dcf/res/ark:/67717/Matiere',
                                        ark_naa=testutils.naa(cnx))
diff --git a/test/unittest_sobjects_skos.py b/test/unittest_sobjects_skos.py
--- a/test/unittest_sobjects_skos.py
+++ b/test/unittest_sobjects_skos.py
@@ -93,8 +93,8 @@ class LCSVImportTC(CubicWebTC):
                              delimiter='\t', encoding='utf-8', language_code='es')
             concept1 = cnx.find(
                 'Concept', definition="Définition de l'organisation politique de l'organisme").one()
-            self.assertEqual(concept1.cwuri,
-                             'ark:/0/rf%09dg' % concept1.eid)
+            self.assertTrue(testutils.match_ark_uri(concept1.cwuri),
+                            concept1.cwuri)
 
 
 if __name__ == '__main__':


More information about the saem-devel mailing list