You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@subversion.apache.org by br...@apache.org on 2013/07/06 15:17:59 UTC

svn commit: r1500255 - in /subversion/trunk/subversion/bindings/javahl: native/ tests/org/apache/subversion/javahl/

Author: brane
Date: Sat Jul  6 13:17:59 2013
New Revision: 1500255

URL: http://svn.apache.org/r1500255
Log:
Fixed the JavaHL RA implementation, infrastructure and tests so that they
all pass via ra_serf and ra_svn (on a local connection with trunk servers).

[in subversion/bindings/javahl/native]
* JNIUtil.cpp (JNIUtil::makeJByteArray): Check for null svn_string_t.

* CommitEditor.h
  (CommitEditor::provide_base_cb, CommitEditor::provide_props_cb): New methods.
* CommitEditor.cpp (open_callback_session): Extracted code for opening the
   secondary session that suuports the Ev2 commit editor callbakcs from
   CommitEditor::get_copysrc_kind_cb.
  (CommitEditor::provide_base_cb, CommitEditor::provide_props_cb): Implement.
  (CommitEditor::CommitEditor): Use the new callbacks.

[in subversion/bindings/javahl/tests/org/apache/subversion/javahl]
* BasicTests.java (BasicTests.CountingProgressListener): New private class;
   hoisted from BasicTests.testDataTransferProgressReport to avoid
   throwing exceptions through native callbacks, which clutter up the
   output during the test run.
  (BasicTests.testDataTransferProgressReport): Use the new callback class.

* SVNRemoteTests.java
  (SVNRemoteTests.testChangeRevpropAtomic): Check list of allowed error codes.
  (SVNRemoteTests.testGetFile, SVNRemoteTests.testGetDirectory): Expect wcprops.
  (SVNRemoteTests.testEditorSetFileContents): New test case; covers a code path
   that had not been tested before.
  (SVNRemoteTests.testEditorSetFileProps): Replaced by testEditorSetFileContents.
  (SVNRemoteTests.RemoteStatusReceiver): Make StatInfo array sortable.
  (SVNRemoteTests.testPropchangeStatus,
   SVNRemoteTests.testDeletedStatus): Sort status entries before checking
   results because ra_serf sends them in the opposite order than ra_local.
* SVNTests.java (SVNTests.prompt): Return true; we do have credentials info.

Modified:
    subversion/trunk/subversion/bindings/javahl/native/CommitEditor.cpp
    subversion/trunk/subversion/bindings/javahl/native/CommitEditor.h
    subversion/trunk/subversion/bindings/javahl/native/JNIUtil.cpp
    subversion/trunk/subversion/bindings/javahl/tests/org/apache/subversion/javahl/BasicTests.java
    subversion/trunk/subversion/bindings/javahl/tests/org/apache/subversion/javahl/SVNRemoteTests.java
    subversion/trunk/subversion/bindings/javahl/tests/org/apache/subversion/javahl/SVNTests.java

Modified: subversion/trunk/subversion/bindings/javahl/native/CommitEditor.cpp
URL: http://svn.apache.org/viewvc/subversion/trunk/subversion/bindings/javahl/native/CommitEditor.cpp?rev=1500255&r1=1500254&r2=1500255&view=diff
==============================================================================
--- subversion/trunk/subversion/bindings/javahl/native/CommitEditor.cpp (original)
+++ subversion/trunk/subversion/bindings/javahl/native/CommitEditor.cpp Sat Jul  6 13:17:59 2013
@@ -69,7 +69,6 @@ CommitEditor::createInstance(jobject jse
   return editor->getCppAddr();
 }
 
-
 CommitEditor::CommitEditor(RemoteSession* session,
                            jobject jrevprops, jobject jcommit_callback,
                            jobject jlock_tokens, jboolean jkeep_locks)
@@ -105,8 +104,8 @@ CommitEditor::CommitEditor(RemoteSession
                   m_callback.callback, &m_callback,
                   lock_tokens.hash(subPool, true),
                   bool(jkeep_locks),
-                  NULL,               // svn_ra__provide_base_cb_t
-                  NULL,               // svn_ra__provide_props_cb_t
+                  this->provide_base_cb,
+                  this->provide_props_cb,
                   this->get_copysrc_kind_cb, this,
                   pool.getPool(),     // result pool
                   subPool.getPool()), // scratch pool
@@ -487,23 +486,20 @@ void CommitEditor::abort()
 }
 
 
-svn_error_t*
-CommitEditor::get_copysrc_kind_cb(svn_node_kind_t* kind, void* baton,
-                                  const char* repos_relpath,
-                                  svn_revnum_t src_revision,
-                                  apr_pool_t *scratch_pool)
+namespace {
+svn_error_t* open_callback_session(svn_ra_session_t*& session,
+                                   const char* url, const char* uuid,
+                                   RemoteSessionContext* context,
+                                   SVN::Pool& sessionPool)
 {
-  CommitEditor* editor = static_cast<CommitEditor*>(baton);
-  if (!editor->m_callback_session)
+  if (!session)
     {
-      const char* corrected_url;
-      SVN_ERR(svn_ra_open4(&editor->m_callback_session, &corrected_url,
-                           editor->m_callback_session_url,
-                           editor->m_callback_session_uuid,
-                           editor->m_session->m_context->getCallbacks(),
-                           editor->m_session->m_context->getCallbackBaton(),
-                           editor->m_session->m_context->getConfigData(),
-                           editor->pool.getPool()));
+      const char* corrected_url = NULL;
+      SVN_ERR(svn_ra_open4(&session, &corrected_url, url, uuid,
+                           context->getCallbacks(),
+                           context->getCallbackBaton(),
+                           context->getConfigData(),
+                           sessionPool.getPool()));
 
       if (corrected_url)
         {
@@ -515,12 +511,79 @@ CommitEditor::get_copysrc_kind_cb(svn_no
               SVN_ERR_RA_ILLEGAL_URL, NULL,
               _("Repository URL changed while session was open.\n"
                 "Expected URL: %s\nApparent URL: %s"),
-              editor->m_callback_session_url, corrected_url);
+              url, corrected_url);
         }
     }
+  return SVN_NO_ERROR;
+}
+} // anonymous namespace
+
+
+svn_error_t*
+CommitEditor::provide_base_cb(svn_stream_t **contents,
+                              svn_revnum_t *revision,
+                              void *baton,
+                              const char *repos_relpath,
+                              apr_pool_t *result_pool,
+                              apr_pool_t *scratch_pool)
+{
+  *contents = NULL;
+  *revision = NULL;
+  return SVN_NO_ERROR;
+}
+
+svn_error_t*
+CommitEditor::provide_props_cb(apr_hash_t **props,
+                               svn_revnum_t *revision,
+                               void *baton,
+                               const char *repos_relpath,
+                               apr_pool_t *result_pool,
+                               apr_pool_t *scratch_pool)
+{
+  CommitEditor* editor = static_cast<CommitEditor*>(baton);
+  SVN_ERR(open_callback_session(editor->m_callback_session,
+                                editor->m_callback_session_url,
+                                editor->m_callback_session_uuid,
+                                editor->m_session->m_context,
+                                editor->pool));
+
+  svn_node_kind_t kind = svn_node_unknown;
+  SVN_ERR(svn_ra_check_path(editor->m_callback_session,
+                            repos_relpath, SVN_INVALID_REVNUM, &kind,
+                            scratch_pool));
+
+  // FIXME: Getting properties from the youngest revision is in fact
+  // not such a bright idea, as the path may have been moved or
+  // deleted in the path.
+  if (kind == svn_node_file)
+    return svn_ra_get_file(editor->m_callback_session,
+                           repos_relpath, SVN_INVALID_REVNUM,
+                           NULL, revision, props, scratch_pool);
+  else if (kind == svn_node_dir)
+    return svn_ra_get_dir2(editor->m_callback_session, NULL, revision, props,
+                           repos_relpath, SVN_INVALID_REVNUM, 0, scratch_pool);
+  else
+    return svn_error_createf(SVN_ERR_NODE_UNEXPECTED_KIND, NULL,
+                             _("Expected node kind '%s' or '%s' but got '%s'"),
+                             svn_node_kind_to_word(svn_node_file),
+                             svn_node_kind_to_word(svn_node_dir),
+                             svn_node_kind_to_word(kind));
+}
+
+svn_error_t*
+CommitEditor::get_copysrc_kind_cb(svn_node_kind_t* kind, void* baton,
+                                  const char* repos_relpath,
+                                  svn_revnum_t src_revision,
+                                  apr_pool_t *scratch_pool)
+{
+  CommitEditor* editor = static_cast<CommitEditor*>(baton);
+  SVN_ERR(open_callback_session(editor->m_callback_session,
+                                editor->m_callback_session_url,
+                                editor->m_callback_session_uuid,
+                                editor->m_session->m_context,
+                                editor->pool));
 
-  SVN::Pool subPool(editor->pool);
   return svn_ra_check_path(editor->m_callback_session,
                            repos_relpath, src_revision, kind,
-                           subPool.getPool());
+                           scratch_pool);
 }

Modified: subversion/trunk/subversion/bindings/javahl/native/CommitEditor.h
URL: http://svn.apache.org/viewvc/subversion/trunk/subversion/bindings/javahl/native/CommitEditor.h?rev=1500255&r1=1500254&r2=1500255&view=diff
==============================================================================
--- subversion/trunk/subversion/bindings/javahl/native/CommitEditor.h (original)
+++ subversion/trunk/subversion/bindings/javahl/native/CommitEditor.h Sat Jul  6 13:17:59 2013
@@ -90,7 +90,19 @@ private:
                jobject jrevprops, jobject jcommit_callback,
                jobject jlock_tokens, jboolean jkeep_locks);
 
-  // This is our svn_ra__get_copysrc_kind_cb_t for the commit editor.
+  // This is our private callbacks for the commit editor.
+  static svn_error_t* provide_base_cb(svn_stream_t **contents,
+                                      svn_revnum_t *revision,
+                                      void *baton,
+                                      const char *repos_relpath,
+                                      apr_pool_t *result_pool,
+                                      apr_pool_t *scratch_pool);
+  static svn_error_t* provide_props_cb(apr_hash_t **props,
+                                       svn_revnum_t *revision,
+                                       void *baton,
+                                       const char *repos_relpath,
+                                       apr_pool_t *result_pool,
+                                       apr_pool_t *scratch_pool);
   static svn_error_t* get_copysrc_kind_cb(svn_node_kind_t* kind, void* baton,
                                           const char* repos_relpath,
                                           svn_revnum_t src_revision,

Modified: subversion/trunk/subversion/bindings/javahl/native/JNIUtil.cpp
URL: http://svn.apache.org/viewvc/subversion/trunk/subversion/bindings/javahl/native/JNIUtil.cpp?rev=1500255&r1=1500254&r2=1500255&view=diff
==============================================================================
--- subversion/trunk/subversion/bindings/javahl/native/JNIUtil.cpp (original)
+++ subversion/trunk/subversion/bindings/javahl/native/JNIUtil.cpp Sat Jul  6 13:17:59 2013
@@ -908,11 +908,9 @@ JNIUtil::getDate(jobject jdate)
  */
 jbyteArray JNIUtil::makeJByteArray(const void *data, int length)
 {
-  if (data == NULL)
-    {
-      // a NULL will create no Java array
-      return NULL;
-    }
+  // a NULL will create no Java array
+  if (!data)
+    return NULL;
 
   JNIEnv *env = getEnv();
 
@@ -943,6 +941,10 @@ jbyteArray JNIUtil::makeJByteArray(const
  */
 jbyteArray JNIUtil::makeJByteArray(const svn_string_t *str)
 {
+  // a NULL will create no Java array
+  if (!str)
+    return NULL;
+
   return JNIUtil::makeJByteArray(str->data, static_cast<int>(str->len));
 }
 

Modified: subversion/trunk/subversion/bindings/javahl/tests/org/apache/subversion/javahl/BasicTests.java
URL: http://svn.apache.org/viewvc/subversion/trunk/subversion/bindings/javahl/tests/org/apache/subversion/javahl/BasicTests.java?rev=1500255&r1=1500254&r2=1500255&view=diff
==============================================================================
--- subversion/trunk/subversion/bindings/javahl/tests/org/apache/subversion/javahl/BasicTests.java (original)
+++ subversion/trunk/subversion/bindings/javahl/tests/org/apache/subversion/javahl/BasicTests.java Sat Jul  6 13:17:59 2013
@@ -3300,6 +3300,16 @@ public class BasicTests extends SVNTests
         }
     }
 
+    private static class CountingProgressListener implements ProgressCallback
+    {
+        public void onProgress(ProgressEvent event)
+        {
+            // TODO: Examine the byte counts from "event".
+            gotProgress = true;
+        }
+        public boolean gotProgress = false;
+    }
+
     public void testDataTransferProgressReport() throws Throwable
     {
         // ### FIXME: This isn't working over ra_local, because
@@ -3309,25 +3319,13 @@ public class BasicTests extends SVNTests
 
         // build the test setup
         OneTest thisTest = new OneTest();
-        ProgressCallback listener = new ProgressCallback()
-        {
-            public void onProgress(ProgressEvent event)
-            {
-                // TODO: Examine the byte counts from "event".
-                throw new RuntimeException("Progress reported as expected");
-            }
-        };
+        CountingProgressListener listener = new CountingProgressListener();
         client.setProgressCallback(listener);
 
         // Perform an update to exercise the progress notification.
-        try
-        {
-            update(thisTest);
+        update(thisTest);
+        if (!listener.gotProgress)
             fail("No progress reported");
-        }
-        catch (RuntimeException progressReported)
-        {
-        }
     }
 
     /**

Modified: subversion/trunk/subversion/bindings/javahl/tests/org/apache/subversion/javahl/SVNRemoteTests.java
URL: http://svn.apache.org/viewvc/subversion/trunk/subversion/bindings/javahl/tests/org/apache/subversion/javahl/SVNRemoteTests.java?rev=1500255&r1=1500254&r2=1500255&view=diff
==============================================================================
--- subversion/trunk/subversion/bindings/javahl/tests/org/apache/subversion/javahl/SVNRemoteTests.java (original)
+++ subversion/trunk/subversion/bindings/javahl/tests/org/apache/subversion/javahl/SVNRemoteTests.java Sat Jul  6 13:17:59 2013
@@ -29,6 +29,7 @@ import org.apache.subversion.javahl.type
 
 import java.util.Arrays;
 import java.util.ArrayList;
+import java.util.Collections;
 import java.util.Date;
 import java.util.List;
 import java.util.Set;
@@ -308,8 +309,20 @@ public class SVNRemoteTests extends SVNT
         }
         catch (ClientException ex)
         {
-            assertEquals("Disabled repository feature",
-                         ex.getAllMessages().get(0).getMessage());
+            ClientException.ErrorMessage error = null;
+            for (ClientException.ErrorMessage m : ex.getAllMessages())
+                if (!m.isGeneric()) {
+                    error = m;
+                    break;
+                }
+
+            if (error == null)
+                fail("Failed with no error message");
+
+            if (error.getCode() != 175002 && // SVN_ERR_RA_DAV_REQUEST_FAILED
+                error.getCode() != 165006)   // SVN_ERR_REPOS_DISABLED_FEATURE
+                fail(error.getMessage());
+
             return;
         }
 
@@ -351,8 +364,11 @@ public class SVNRemoteTests extends SVNT
         assertEquals(fetched_rev, 1);
         assertEquals(contents.toString("UTF-8"),
                      "This is the file 'lambda'.");
-        for (Map.Entry<String, byte[]> e : properties.entrySet())
-            assertTrue(e.getKey().startsWith("svn:entry:"));
+        for (Map.Entry<String, byte[]> e : properties.entrySet()) {
+            final String key = e.getKey();
+            assertTrue(key.startsWith("svn:entry:")
+                       || key.startsWith("svn:wc:"));
+        }
     }
 
     public void testGetDirectory() throws Exception
@@ -373,8 +389,11 @@ public class SVNRemoteTests extends SVNT
         assertEquals(dirents.get("E").getPath(), "E");
         assertEquals(dirents.get("F").getPath(), "F");
         assertEquals(dirents.get("lambda").getPath(), "lambda");
-        for (Map.Entry<String, byte[]> e : properties.entrySet())
-            assertTrue(e.getKey().startsWith("svn:entry:"));
+        for (Map.Entry<String, byte[]> e : properties.entrySet()) {
+            final String key = e.getKey();
+            assertTrue(key.startsWith("svn:entry:")
+                       || key.startsWith("svn:wc:"));
+        }
     }
 
     private final class CommitContext implements CommitCallback
@@ -574,19 +593,19 @@ public class SVNRemoteTests extends SVNT
         assertTrue(Arrays.equals(eolstyle, propval));
     }
 
-    public void testEditorSetFileProps() throws Exception
+    public void testEditorSetFileContents() throws Exception
     {
         Charset UTF8 = Charset.forName("UTF-8");
         ISVNRemote session = getSession();
 
-        byte[] eolstyle = "CRLF".getBytes(UTF8);
-        HashMap<String, byte[]> props = new HashMap<String, byte[]>();
-        props.put("svn:eol-style", eolstyle);
+        byte[] contents = "This is modified file 'alpha'.".getBytes(UTF8);
+        Checksum hash = new Checksum(SHA1(contents), Checksum.Kind.SHA1);
+        ByteArrayInputStream stream = new ByteArrayInputStream(contents);
 
         CommitContext cc =
-            new CommitContext(session, "Change eol-style on A/B/E/alpha");
+            new CommitContext(session, "Change contents of A/B/E/alpha");
         try {
-            cc.editor.alterFile("A/B/E/alpha", 1, null, null, props);
+            cc.editor.alterFile("A/B/E/alpha", 1, hash, stream, null);
             cc.editor.complete();
         } finally {
             cc.editor.dispose();
@@ -594,12 +613,10 @@ public class SVNRemoteTests extends SVNT
 
         assertEquals(2, cc.getRevision());
         assertEquals(2, session.getLatestRevision());
-        byte[] propval = client.propertyGet(session.getSessionUrl()
-                                            + "/A/B/E/alpha",
-                                            "svn:eol-style",
-                                            Revision.HEAD,
-                                            Revision.HEAD);
-        assertTrue(Arrays.equals(eolstyle, propval));
+        ByteArrayOutputStream checkcontents = new ByteArrayOutputStream();
+        client.streamFileContent(session.getSessionUrl() + "/A/B/E/alpha",
+                                 Revision.HEAD, Revision.HEAD, checkcontents);
+        assertTrue(Arrays.equals(contents, checkcontents.toByteArray()));
     }
 
     // public void testEditorRotate() throws Exception
@@ -787,7 +804,7 @@ public class SVNRemoteTests extends SVNT
 
     private static class RemoteStatusReceiver implements RemoteStatus
     {
-        static class StatInfo
+        static class StatInfo implements Comparable<StatInfo>
         {
             public String relpath = null;
             public char kind = ' '; // F, D, L
@@ -813,6 +830,18 @@ public class SVNRemoteTests extends SVNT
                 this.propsChanged = propsChanged;
                 this.info = info;
             }
+
+            @Override
+            public boolean equals(Object statinfo)
+            {
+                final StatInfo that = (StatInfo)statinfo;
+                return this.relpath.equals(that.relpath);
+            }
+
+            public int compareTo(StatInfo that)
+            {
+                return this.relpath.compareTo(that.relpath);
+            }
         }
 
         private boolean debug;
@@ -946,7 +975,11 @@ public class SVNRemoteTests extends SVNT
         } finally {
             rp.dispose();
         }
+
         assertEquals(4, receiver.status.size());
+
+        // ra_serf returns the entries in inverted order compared to ra_local.
+        Collections.sort(receiver.status);
         RemoteStatusReceiver.StatInfo mod = receiver.status.get(3);
         assertEquals("A/D/gamma", mod.relpath);
         assertEquals('F', mod.kind);
@@ -979,6 +1012,9 @@ public class SVNRemoteTests extends SVNT
             rp.dispose();
         }
         assertEquals(3, receiver.status.size());
+
+        // ra_serf returns the entries in inverted order compared to ra_local.
+        Collections.sort(receiver.status);
         RemoteStatusReceiver.StatInfo mod = receiver.status.get(2);
         assertEquals("A/mu", mod.relpath);
         assertEquals(' ', mod.kind);

Modified: subversion/trunk/subversion/bindings/javahl/tests/org/apache/subversion/javahl/SVNTests.java
URL: http://svn.apache.org/viewvc/subversion/trunk/subversion/bindings/javahl/tests/org/apache/subversion/javahl/SVNTests.java?rev=1500255&r1=1500254&r2=1500255&view=diff
==============================================================================
--- subversion/trunk/subversion/bindings/javahl/tests/org/apache/subversion/javahl/SVNTests.java (original)
+++ subversion/trunk/subversion/bindings/javahl/tests/org/apache/subversion/javahl/SVNTests.java Sat Jul  6 13:17:59 2013
@@ -324,12 +324,12 @@ class SVNTests extends TestCase
 
         public boolean prompt(String realm, String username)
         {
-            return false;
+            return true;
         }
 
         public boolean prompt(String realm, String username, boolean maySave)
         {
-            return false;
+            return true;
         }
 
         public String askQuestion(String realm, String question,