hgitaly 18.7.1__tar.gz → 18.7.2__tar.gz

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (175) hide show
  1. {hgitaly-18.7.1/hgitaly.egg-info → hgitaly-18.7.2}/PKG-INFO +1 -1
  2. {hgitaly-18.7.1 → hgitaly-18.7.2}/functional_tests/test_blob_tree.py +1 -1
  3. {hgitaly-18.7.1 → hgitaly-18.7.2}/functional_tests/test_commit.py +11 -2
  4. {hgitaly-18.7.1 → hgitaly-18.7.2}/functional_tests/test_ref.py +14 -0
  5. hgitaly-18.7.2/hgitaly/VERSION +1 -0
  6. hgitaly-18.7.2/hgitaly/scripts/__init__.py +3 -0
  7. hgitaly-18.7.2/hgitaly/scripts/load_tests.py +373 -0
  8. {hgitaly-18.7.1 → hgitaly-18.7.2/hgitaly.egg-info}/PKG-INFO +1 -1
  9. {hgitaly-18.7.1 → hgitaly-18.7.2}/hgitaly.egg-info/SOURCES.txt +3 -1
  10. {hgitaly-18.7.1 → hgitaly-18.7.2}/hgitaly.egg-info/entry_points.txt +1 -0
  11. {hgitaly-18.7.1 → hgitaly-18.7.2}/setup.py +1 -0
  12. hgitaly-18.7.1/hgitaly/VERSION +0 -1
  13. {hgitaly-18.7.1 → hgitaly-18.7.2}/LICENSE +0 -0
  14. {hgitaly-18.7.1 → hgitaly-18.7.2}/MANIFEST.in +0 -0
  15. {hgitaly-18.7.1 → hgitaly-18.7.2}/README.md +0 -0
  16. {hgitaly-18.7.1 → hgitaly-18.7.2}/functional_tests/__init__.py +0 -0
  17. {hgitaly-18.7.1 → hgitaly-18.7.2}/functional_tests/comparison.py +0 -0
  18. {hgitaly-18.7.1 → hgitaly-18.7.2}/functional_tests/conftest.py +0 -0
  19. {hgitaly-18.7.1 → hgitaly-18.7.2}/functional_tests/gitaly.py +0 -0
  20. {hgitaly-18.7.1 → hgitaly-18.7.2}/functional_tests/hgitaly_rhgitaly_comparison.py +0 -0
  21. {hgitaly-18.7.1 → hgitaly-18.7.2}/functional_tests/rhgitaly.py +0 -0
  22. {hgitaly-18.7.1 → hgitaly-18.7.2}/functional_tests/test_comparison.py +0 -0
  23. {hgitaly-18.7.1 → hgitaly-18.7.2}/functional_tests/test_diff.py +0 -0
  24. {hgitaly-18.7.1 → hgitaly-18.7.2}/functional_tests/test_gitaly_server.py +0 -0
  25. {hgitaly-18.7.1 → hgitaly-18.7.2}/functional_tests/test_mercurial_aux_git.py +0 -0
  26. {hgitaly-18.7.1 → hgitaly-18.7.2}/functional_tests/test_mercurial_operations.py +0 -0
  27. {hgitaly-18.7.1 → hgitaly-18.7.2}/functional_tests/test_mercurial_repository.py +0 -0
  28. {hgitaly-18.7.1 → hgitaly-18.7.2}/functional_tests/test_operations.py +0 -0
  29. {hgitaly-18.7.1 → hgitaly-18.7.2}/functional_tests/test_remote.py +0 -0
  30. {hgitaly-18.7.1 → hgitaly-18.7.2}/functional_tests/test_repository_service.py +0 -0
  31. {hgitaly-18.7.1 → hgitaly-18.7.2}/functional_tests/test_rhgitaly_server.py +0 -0
  32. {hgitaly-18.7.1 → hgitaly-18.7.2}/functional_tests/test_server.py +0 -0
  33. {hgitaly-18.7.1 → hgitaly-18.7.2}/hgext3rd/__init__.py +0 -0
  34. {hgitaly-18.7.1 → hgitaly-18.7.2}/hgext3rd/hgitaly/__init__.py +0 -0
  35. {hgitaly-18.7.1 → hgitaly-18.7.2}/hgext3rd/hgitaly/revset.py +0 -0
  36. {hgitaly-18.7.1 → hgitaly-18.7.2}/hgext3rd/hgitaly/tests/__init__.py +0 -0
  37. {hgitaly-18.7.1 → hgitaly-18.7.2}/hgext3rd/hgitaly/tests/test_revset.py +0 -0
  38. {hgitaly-18.7.1 → hgitaly-18.7.2}/hgext3rd/hgitaly/tests/test_serve.py +0 -0
  39. {hgitaly-18.7.1 → hgitaly-18.7.2}/hgitaly/__init__.py +0 -0
  40. {hgitaly-18.7.1 → hgitaly-18.7.2}/hgitaly/branch.py +0 -0
  41. {hgitaly-18.7.1 → hgitaly-18.7.2}/hgitaly/changelog.py +0 -0
  42. {hgitaly-18.7.1 → hgitaly-18.7.2}/hgitaly/diff.py +0 -0
  43. {hgitaly-18.7.1 → hgitaly-18.7.2}/hgitaly/errors.py +0 -0
  44. {hgitaly-18.7.1 → hgitaly-18.7.2}/hgitaly/feature.py +0 -0
  45. {hgitaly-18.7.1 → hgitaly-18.7.2}/hgitaly/file_content.py +0 -0
  46. {hgitaly-18.7.1 → hgitaly-18.7.2}/hgitaly/file_context.py +0 -0
  47. {hgitaly-18.7.1 → hgitaly-18.7.2}/hgitaly/git.py +0 -0
  48. {hgitaly-18.7.1 → hgitaly-18.7.2}/hgitaly/gitlab_ref.py +0 -0
  49. {hgitaly-18.7.1 → hgitaly-18.7.2}/hgitaly/identification.py +0 -0
  50. {hgitaly-18.7.1 → hgitaly-18.7.2}/hgitaly/logging.py +0 -0
  51. {hgitaly-18.7.1 → hgitaly-18.7.2}/hgitaly/manifest.py +0 -0
  52. {hgitaly-18.7.1 → hgitaly-18.7.2}/hgitaly/message.py +0 -0
  53. {hgitaly-18.7.1 → hgitaly-18.7.2}/hgitaly/oid.py +0 -0
  54. {hgitaly-18.7.1 → hgitaly-18.7.2}/hgitaly/pagination.py +0 -0
  55. {hgitaly-18.7.1 → hgitaly-18.7.2}/hgitaly/path.py +0 -0
  56. {hgitaly-18.7.1 → hgitaly-18.7.2}/hgitaly/peer.py +0 -0
  57. {hgitaly-18.7.1 → hgitaly-18.7.2}/hgitaly/procutil.py +0 -0
  58. {hgitaly-18.7.1 → hgitaly-18.7.2}/hgitaly/repository.py +0 -0
  59. {hgitaly-18.7.1 → hgitaly-18.7.2}/hgitaly/revision.py +0 -0
  60. {hgitaly-18.7.1 → hgitaly-18.7.2}/hgitaly/revset.py +0 -0
  61. /hgitaly-18.7.1/hgitaly/scripts.py → /hgitaly-18.7.2/hgitaly/scripts/stats.py +0 -0
  62. {hgitaly-18.7.1 → hgitaly-18.7.2}/hgitaly/server/__init__.py +0 -0
  63. {hgitaly-18.7.1 → hgitaly-18.7.2}/hgitaly/server/address.py +0 -0
  64. {hgitaly-18.7.1 → hgitaly-18.7.2}/hgitaly/server/mono.py +0 -0
  65. {hgitaly-18.7.1 → hgitaly-18.7.2}/hgitaly/server/tests/__init__.py +0 -0
  66. {hgitaly-18.7.1 → hgitaly-18.7.2}/hgitaly/server/tests/test_address.py +0 -0
  67. {hgitaly-18.7.1 → hgitaly-18.7.2}/hgitaly/server/tests/test_mono.py +0 -0
  68. {hgitaly-18.7.1 → hgitaly-18.7.2}/hgitaly/server/tests/test_worker.py +0 -0
  69. {hgitaly-18.7.1 → hgitaly-18.7.2}/hgitaly/server/worker.py +0 -0
  70. {hgitaly-18.7.1 → hgitaly-18.7.2}/hgitaly/service/__init__.py +0 -0
  71. {hgitaly-18.7.1 → hgitaly-18.7.2}/hgitaly/service/analysis.py +0 -0
  72. {hgitaly-18.7.1 → hgitaly-18.7.2}/hgitaly/service/blob.py +0 -0
  73. {hgitaly-18.7.1 → hgitaly-18.7.2}/hgitaly/service/commit.py +0 -0
  74. {hgitaly-18.7.1 → hgitaly-18.7.2}/hgitaly/service/diff.py +0 -0
  75. {hgitaly-18.7.1 → hgitaly-18.7.2}/hgitaly/service/interceptors.py +0 -0
  76. {hgitaly-18.7.1 → hgitaly-18.7.2}/hgitaly/service/mercurial_changeset.py +0 -0
  77. {hgitaly-18.7.1 → hgitaly-18.7.2}/hgitaly/service/mercurial_namespace.py +0 -0
  78. {hgitaly-18.7.1 → hgitaly-18.7.2}/hgitaly/service/mercurial_operations.py +0 -0
  79. {hgitaly-18.7.1 → hgitaly-18.7.2}/hgitaly/service/mercurial_repository.py +0 -0
  80. {hgitaly-18.7.1 → hgitaly-18.7.2}/hgitaly/service/operations.py +0 -0
  81. {hgitaly-18.7.1 → hgitaly-18.7.2}/hgitaly/service/ref.py +0 -0
  82. {hgitaly-18.7.1 → hgitaly-18.7.2}/hgitaly/service/repository.py +0 -0
  83. {hgitaly-18.7.1 → hgitaly-18.7.2}/hgitaly/service/server.py +0 -0
  84. {hgitaly-18.7.1 → hgitaly-18.7.2}/hgitaly/service/tests/__init__.py +0 -0
  85. {hgitaly-18.7.1 → hgitaly-18.7.2}/hgitaly/service/tests/fixture.py +0 -0
  86. {hgitaly-18.7.1 → hgitaly-18.7.2}/hgitaly/service/tests/test_analysis.py +0 -0
  87. {hgitaly-18.7.1 → hgitaly-18.7.2}/hgitaly/service/tests/test_blob.py +0 -0
  88. {hgitaly-18.7.1 → hgitaly-18.7.2}/hgitaly/service/tests/test_commit.py +0 -0
  89. {hgitaly-18.7.1 → hgitaly-18.7.2}/hgitaly/service/tests/test_default_branch.py +0 -0
  90. {hgitaly-18.7.1 → hgitaly-18.7.2}/hgitaly/service/tests/test_diff.py +0 -0
  91. {hgitaly-18.7.1 → hgitaly-18.7.2}/hgitaly/service/tests/test_mercurial_changeset.py +0 -0
  92. {hgitaly-18.7.1 → hgitaly-18.7.2}/hgitaly/service/tests/test_mercurial_namespace.py +0 -0
  93. {hgitaly-18.7.1 → hgitaly-18.7.2}/hgitaly/service/tests/test_mercurial_operations.py +0 -0
  94. {hgitaly-18.7.1 → hgitaly-18.7.2}/hgitaly/service/tests/test_mercurial_repository.py +0 -0
  95. {hgitaly-18.7.1 → hgitaly-18.7.2}/hgitaly/service/tests/test_operations.py +0 -0
  96. {hgitaly-18.7.1 → hgitaly-18.7.2}/hgitaly/service/tests/test_ref.py +0 -0
  97. {hgitaly-18.7.1 → hgitaly-18.7.2}/hgitaly/service/tests/test_repository_service.py +0 -0
  98. {hgitaly-18.7.1 → hgitaly-18.7.2}/hgitaly/service/tests/test_server.py +0 -0
  99. {hgitaly-18.7.1 → hgitaly-18.7.2}/hgitaly/servicer.py +0 -0
  100. {hgitaly-18.7.1 → hgitaly-18.7.2}/hgitaly/ssh.py +0 -0
  101. {hgitaly-18.7.1 → hgitaly-18.7.2}/hgitaly/stream.py +0 -0
  102. {hgitaly-18.7.1 → hgitaly-18.7.2}/hgitaly/stub/__init__.py +0 -0
  103. {hgitaly-18.7.1 → hgitaly-18.7.2}/hgitaly/stub/analysis_pb2.py +0 -0
  104. {hgitaly-18.7.1 → hgitaly-18.7.2}/hgitaly/stub/analysis_pb2_grpc.py +0 -0
  105. {hgitaly-18.7.1 → hgitaly-18.7.2}/hgitaly/stub/blob_pb2.py +0 -0
  106. {hgitaly-18.7.1 → hgitaly-18.7.2}/hgitaly/stub/blob_pb2_grpc.py +0 -0
  107. {hgitaly-18.7.1 → hgitaly-18.7.2}/hgitaly/stub/commit_pb2.py +0 -0
  108. {hgitaly-18.7.1 → hgitaly-18.7.2}/hgitaly/stub/commit_pb2_grpc.py +0 -0
  109. {hgitaly-18.7.1 → hgitaly-18.7.2}/hgitaly/stub/diff_pb2.py +0 -0
  110. {hgitaly-18.7.1 → hgitaly-18.7.2}/hgitaly/stub/diff_pb2_grpc.py +0 -0
  111. {hgitaly-18.7.1 → hgitaly-18.7.2}/hgitaly/stub/errors_pb2.py +0 -0
  112. {hgitaly-18.7.1 → hgitaly-18.7.2}/hgitaly/stub/errors_pb2_grpc.py +0 -0
  113. {hgitaly-18.7.1 → hgitaly-18.7.2}/hgitaly/stub/lint_pb2.py +0 -0
  114. {hgitaly-18.7.1 → hgitaly-18.7.2}/hgitaly/stub/lint_pb2_grpc.py +0 -0
  115. {hgitaly-18.7.1 → hgitaly-18.7.2}/hgitaly/stub/mercurial_aux_git_pb2.py +0 -0
  116. {hgitaly-18.7.1 → hgitaly-18.7.2}/hgitaly/stub/mercurial_aux_git_pb2_grpc.py +0 -0
  117. {hgitaly-18.7.1 → hgitaly-18.7.2}/hgitaly/stub/mercurial_changeset_pb2.py +0 -0
  118. {hgitaly-18.7.1 → hgitaly-18.7.2}/hgitaly/stub/mercurial_changeset_pb2_grpc.py +0 -0
  119. {hgitaly-18.7.1 → hgitaly-18.7.2}/hgitaly/stub/mercurial_namespace_pb2.py +0 -0
  120. {hgitaly-18.7.1 → hgitaly-18.7.2}/hgitaly/stub/mercurial_namespace_pb2_grpc.py +0 -0
  121. {hgitaly-18.7.1 → hgitaly-18.7.2}/hgitaly/stub/mercurial_operations_pb2.py +0 -0
  122. {hgitaly-18.7.1 → hgitaly-18.7.2}/hgitaly/stub/mercurial_operations_pb2_grpc.py +0 -0
  123. {hgitaly-18.7.1 → hgitaly-18.7.2}/hgitaly/stub/mercurial_repository_pb2.py +0 -0
  124. {hgitaly-18.7.1 → hgitaly-18.7.2}/hgitaly/stub/mercurial_repository_pb2_grpc.py +0 -0
  125. {hgitaly-18.7.1 → hgitaly-18.7.2}/hgitaly/stub/operations_pb2.py +0 -0
  126. {hgitaly-18.7.1 → hgitaly-18.7.2}/hgitaly/stub/operations_pb2_grpc.py +0 -0
  127. {hgitaly-18.7.1 → hgitaly-18.7.2}/hgitaly/stub/ref_pb2.py +0 -0
  128. {hgitaly-18.7.1 → hgitaly-18.7.2}/hgitaly/stub/ref_pb2_grpc.py +0 -0
  129. {hgitaly-18.7.1 → hgitaly-18.7.2}/hgitaly/stub/remote_pb2.py +0 -0
  130. {hgitaly-18.7.1 → hgitaly-18.7.2}/hgitaly/stub/remote_pb2_grpc.py +0 -0
  131. {hgitaly-18.7.1 → hgitaly-18.7.2}/hgitaly/stub/repository_pb2.py +0 -0
  132. {hgitaly-18.7.1 → hgitaly-18.7.2}/hgitaly/stub/repository_pb2_grpc.py +0 -0
  133. {hgitaly-18.7.1 → hgitaly-18.7.2}/hgitaly/stub/server_pb2.py +0 -0
  134. {hgitaly-18.7.1 → hgitaly-18.7.2}/hgitaly/stub/server_pb2_grpc.py +0 -0
  135. {hgitaly-18.7.1 → hgitaly-18.7.2}/hgitaly/stub/shared_pb2.py +0 -0
  136. {hgitaly-18.7.1 → hgitaly-18.7.2}/hgitaly/stub/shared_pb2_grpc.py +0 -0
  137. {hgitaly-18.7.1 → hgitaly-18.7.2}/hgitaly/tag.py +0 -0
  138. {hgitaly-18.7.1 → hgitaly-18.7.2}/hgitaly/testing/__init__.py +0 -0
  139. {hgitaly-18.7.1 → hgitaly-18.7.2}/hgitaly/testing/bundle.py +0 -0
  140. {hgitaly-18.7.1 → hgitaly-18.7.2}/hgitaly/testing/context.py +0 -0
  141. {hgitaly-18.7.1 → hgitaly-18.7.2}/hgitaly/testing/grpc.py +0 -0
  142. {hgitaly-18.7.1 → hgitaly-18.7.2}/hgitaly/testing/multiprocessing.py +0 -0
  143. {hgitaly-18.7.1 → hgitaly-18.7.2}/hgitaly/testing/repo.py +0 -0
  144. {hgitaly-18.7.1 → hgitaly-18.7.2}/hgitaly/testing/ssh.py +0 -0
  145. {hgitaly-18.7.1 → hgitaly-18.7.2}/hgitaly/testing/sshd.py +0 -0
  146. {hgitaly-18.7.1 → hgitaly-18.7.2}/hgitaly/testing/storage.py +0 -0
  147. {hgitaly-18.7.1 → hgitaly-18.7.2}/hgitaly/testing/tests/__init__.py +0 -0
  148. {hgitaly-18.7.1 → hgitaly-18.7.2}/hgitaly/testing/tests/test_sshd.py +0 -0
  149. {hgitaly-18.7.1 → hgitaly-18.7.2}/hgitaly/tests/__init__.py +0 -0
  150. {hgitaly-18.7.1 → hgitaly-18.7.2}/hgitaly/tests/common.py +0 -0
  151. {hgitaly-18.7.1 → hgitaly-18.7.2}/hgitaly/tests/test_branch.py +0 -0
  152. {hgitaly-18.7.1 → hgitaly-18.7.2}/hgitaly/tests/test_diff.py +0 -0
  153. {hgitaly-18.7.1 → hgitaly-18.7.2}/hgitaly/tests/test_errors.py +0 -0
  154. {hgitaly-18.7.1 → hgitaly-18.7.2}/hgitaly/tests/test_feature.py +0 -0
  155. {hgitaly-18.7.1 → hgitaly-18.7.2}/hgitaly/tests/test_file_context.py +0 -0
  156. {hgitaly-18.7.1 → hgitaly-18.7.2}/hgitaly/tests/test_gitlab_ref.py +0 -0
  157. {hgitaly-18.7.1 → hgitaly-18.7.2}/hgitaly/tests/test_identification.py +0 -0
  158. {hgitaly-18.7.1 → hgitaly-18.7.2}/hgitaly/tests/test_manifest.py +0 -0
  159. {hgitaly-18.7.1 → hgitaly-18.7.2}/hgitaly/tests/test_messages.py +0 -0
  160. {hgitaly-18.7.1 → hgitaly-18.7.2}/hgitaly/tests/test_oid.py +0 -0
  161. {hgitaly-18.7.1 → hgitaly-18.7.2}/hgitaly/tests/test_peer.py +0 -0
  162. {hgitaly-18.7.1 → hgitaly-18.7.2}/hgitaly/tests/test_repository.py +0 -0
  163. {hgitaly-18.7.1 → hgitaly-18.7.2}/hgitaly/tests/test_revision.py +0 -0
  164. {hgitaly-18.7.1 → hgitaly-18.7.2}/hgitaly/tests/test_revset.py +0 -0
  165. {hgitaly-18.7.1 → hgitaly-18.7.2}/hgitaly/tests/test_servicer.py +0 -0
  166. {hgitaly-18.7.1 → hgitaly-18.7.2}/hgitaly/tests/test_stream.py +0 -0
  167. {hgitaly-18.7.1 → hgitaly-18.7.2}/hgitaly/tests/test_tag.py +0 -0
  168. {hgitaly-18.7.1 → hgitaly-18.7.2}/hgitaly/tests/test_workdir.py +0 -0
  169. {hgitaly-18.7.1 → hgitaly-18.7.2}/hgitaly/util.py +0 -0
  170. {hgitaly-18.7.1 → hgitaly-18.7.2}/hgitaly/workdir.py +0 -0
  171. {hgitaly-18.7.1 → hgitaly-18.7.2}/hgitaly.egg-info/dependency_links.txt +0 -0
  172. {hgitaly-18.7.1 → hgitaly-18.7.2}/hgitaly.egg-info/requires.txt +0 -0
  173. {hgitaly-18.7.1 → hgitaly-18.7.2}/hgitaly.egg-info/top_level.txt +0 -0
  174. {hgitaly-18.7.1 → hgitaly-18.7.2}/install-requirements.txt +0 -0
  175. {hgitaly-18.7.1 → hgitaly-18.7.2}/setup.cfg +0 -0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.1
2
2
  Name: hgitaly
3
- Version: 18.7.1
3
+ Version: 18.7.2
4
4
  Summary: Server-side implementation of Gitaly protocol for Mercurial
5
5
  Home-page: https://foss.heptapod.net/heptapod/hgitaly
6
6
  Author: Georges Racinet
@@ -412,7 +412,7 @@ def test_compare_get_tree_entries_pagination(gitaly_rhgitaly_comparison):
412
412
  # case of unknown revision and limit=0
413
413
  assert_compare_errors(path=b'.', revision=b'unknown',
414
414
  pagination_params=PaginationParameter(limit=0),
415
- skip_structured_errors_issue=156)
415
+ )
416
416
 
417
417
  # case of no pagination params
418
418
  assert_compare_aggregated(path=b'sub',
@@ -41,6 +41,8 @@ if skip_comparison_tests(): # pragma no cover
41
41
 
42
42
  parametrize = pytest.mark.parametrize
43
43
 
44
+ PSEUDO_RANGE_SEPARATORS = (b'..', b'...')
45
+
44
46
 
45
47
  def test_compare_last_commit_for(gitaly_rhgitaly_comparison):
46
48
  fixture = gitaly_rhgitaly_comparison
@@ -594,10 +596,10 @@ def test_compare_count_find_commits(gitaly_rhgitaly_comparison, hg_server):
594
596
  # when `revision` is provided as <revspec>
595
597
  with sorted_comparison():
596
598
  all_revs = [ctx0.hex(), ctx1.hex(), ctx2.hex(), ctx3.hex(), ctx4.hex()]
597
- for range_str in (b'..', b'...'):
599
+ for range_sep in PSEUDO_RANGE_SEPARATORS:
598
600
  for r1 in all_revs:
599
601
  for r2 in all_revs:
600
- assert_compare(revision=r1 + range_str + r2)
602
+ assert_compare(revision=r1 + range_sep + r2)
601
603
 
602
604
  # with message_regex
603
605
  rx = 'FOO.*zoO' # tests case insensitivity
@@ -835,6 +837,13 @@ def test_compare_list_commits(gitaly_rhgitaly_comparison, hg_server):
835
837
 
836
838
  assert_compare(revisions=[ctx4.hex(), caret(ctx1)])
837
839
  assert_compare(revisions=[ctx4.hex(), caret(ctx1)], reverse=True)
840
+ # symmetric difference (HGitaly does not accept pseudo range revisions)
841
+ # this is the only actual testing of `reverse` for RHGitaly many_commits
842
+ symdiff_revspec = b'...'.join((ctx2.hex(), ctx4.hex()))
843
+ if hg_server == 'rhgitaly':
844
+ assert_compare(revisions=[symdiff_revspec])
845
+ assert_compare(revisions=[symdiff_revspec], reverse=True)
846
+
838
847
  # interpretation of several exclusions
839
848
  assert_compare(revisions=[ctx4.hex(), caret(ctx1), caret(ctx2)])
840
849
 
@@ -585,6 +585,9 @@ def test_list_refs(gitaly_rhgitaly_comparison, hg_server):
585
585
  ref_msg.name[len(prefix):])
586
586
  if all_pseudo_ref_idx is not None:
587
587
  del resp.references[all_pseudo_ref_idx]
588
+ if resp.HasField('pagination_cursor'):
589
+ pc = resp.pagination_cursor
590
+ pc.next_cursor = b64decode(pc.next_cursor).decode()
588
591
 
589
592
  rpc_helper = fixture.rpc_helper(
590
593
  hg_server=hg_server,
@@ -631,6 +634,8 @@ def test_list_refs(gitaly_rhgitaly_comparison, hg_server):
631
634
  fixture.write_special_ref(b'pipeline/13', hg_sha)
632
635
  rpc_helper.assert_compare()
633
636
  for head in False, True:
637
+ rpc_helper.assert_compare(patterns=[b'refs/'], head=head)
638
+ rpc_helper.assert_compare(patterns=[b'refs/pipeline/'], head=head)
634
639
  rpc_helper.assert_compare(patterns=[b'refs/heads/'], head=head)
635
640
  rpc_helper.assert_compare(patterns=[b'refs/tags/'], head=head)
636
641
 
@@ -692,6 +697,15 @@ def test_list_refs(gitaly_rhgitaly_comparison, hg_server):
692
697
  head=False,
693
698
  )
694
699
 
700
+ # with pagination parameters (RHGitaly only, HGitaly no longer used)
701
+ paginated = dict(head=False,
702
+ patterns=[b'refs/heads/'], # avoid ALL
703
+ pagination_params=PaginationParameter(limit=2))
704
+ if hg_server == 'rhgitaly':
705
+ rpc_helper.assert_compare(**paginated)
706
+ rpc_helper.assert_compare(sort_by=SortBy(key=SortBy.AUTHORDATE),
707
+ **paginated)
708
+
695
709
  # FindRefsByOID is almost a subset of ListRefs, the only stated
696
710
  # thing that ListRefs would not do is accepting oids by prefix.
697
711
  # So we'll use the same setup
@@ -0,0 +1 @@
1
+ 18.7.2
@@ -0,0 +1,3 @@
1
+ # flake8: noqa F401 (reexports)
2
+ from .stats import stats
3
+ from .load_tests import load_test
@@ -0,0 +1,373 @@
1
+ """Load tests for HGitaly.
2
+
3
+ This simple script assumes that the HGitaly server has a given set of
4
+ repositories:
5
+
6
+ They must absolutely be dedicated to the task, because the load tests
7
+ may involve mutation calls. Hence the script expects the HGitaly server
8
+ to operate on its own separate repositories root and will clone everything
9
+ if needed.
10
+
11
+ Future facilities:
12
+
13
+ - configuring and launching RHGitaly
14
+ """
15
+ import argparse
16
+ import json
17
+ import logging
18
+ import random
19
+ import statistics
20
+ import threading
21
+ import multiprocessing as mp
22
+ import time
23
+ from urllib.parse import urlparse
24
+
25
+ import grpc
26
+
27
+ from hgitaly import feature
28
+ from hgitaly.servicer import (
29
+ SKIP_HOOKS_MD_KEY,
30
+ NATIVE_PROJECT_MD_KEY,
31
+ )
32
+
33
+ from hgitaly.stub.commit_pb2_grpc import CommitServiceStub
34
+ from hgitaly.stub.commit_pb2 import (
35
+ CountCommitsRequest,
36
+ FindCommitsRequest,
37
+ )
38
+ from hgitaly.stub.mercurial_operations_pb2 import (
39
+ InvalidateMergeAnalysisRequest,
40
+ MergeAnalysisRequest,
41
+ )
42
+ from hgitaly.stub.mercurial_operations_pb2_grpc import (
43
+ MercurialOperationsServiceStub,
44
+ )
45
+ from hgitaly.stub.mercurial_repository_pb2_grpc import (
46
+ MercurialRepositoryServiceStub,
47
+ )
48
+ from hgitaly.stub.mercurial_repository_pb2 import (
49
+ HgCallRequest,
50
+ )
51
+ from hgitaly.stub.repository_pb2_grpc import RepositoryServiceStub
52
+ from hgitaly.stub.repository_pb2 import (
53
+ CreateRepositoryRequest,
54
+ RepositoryExistsRequest,
55
+ )
56
+ from hgitaly.stub.shared_pb2 import (
57
+ Repository,
58
+ )
59
+
60
+ FOSS_HEPTAPOD = 'https://foss.heptapod.net'
61
+
62
+ logger = logging.getLogger(__name__)
63
+
64
+
65
+ def gl_repo(relpath):
66
+ return Repository(storage_name='default', relative_path=relpath)
67
+
68
+
69
+ class LoadWorker:
70
+
71
+ weighted_methods = (
72
+ ('find_commits_mercurial_devel', 9),
73
+ ('sleep_a_bit', 1),
74
+ ('merge_analysis_mercurial_devel', 1),
75
+ )
76
+ repositories = {
77
+ 'mercurial-devel': FOSS_HEPTAPOD + '/mercurial/mercurial-devel',
78
+ }
79
+ feature_flags = ()
80
+
81
+ @classmethod
82
+ def compute_random_thresholds(cls):
83
+ total_weight = sum(wm[1] for wm in cls.weighted_methods)
84
+
85
+ thresholds = []
86
+ current = 0
87
+ for meth, weight in cls.weighted_methods:
88
+ thresholds.append((current, meth))
89
+ current += weight / total_weight
90
+ cls.random_thresholds = thresholds
91
+ logger.warning("Random thresholds: %r", thresholds)
92
+
93
+ @classmethod
94
+ def random_method(cls):
95
+ rand = random.random()
96
+ candidate = cls.random_thresholds[0][0]
97
+ for thr, name in cls.random_thresholds:
98
+ if thr > rand:
99
+ break
100
+ candidate = name
101
+ return candidate
102
+
103
+ def __init__(self, url, queue, wid=None):
104
+ self.url = url = urlparse(url)
105
+ self.queue = queue
106
+
107
+ if url.scheme != 'tcp':
108
+ raise RuntimeError("Unsupported URL scheme: %r" % url.scheme)
109
+ if wid is not None:
110
+ logger.info("Worker %d starting", wid)
111
+ self.channel = grpc.insecure_channel(url.netloc)
112
+ self.hg_operations_service = MercurialOperationsServiceStub(
113
+ self.channel)
114
+ self.hg_repository_service = MercurialRepositoryServiceStub(
115
+ self.channel)
116
+ self.repository_service = RepositoryServiceStub(self.channel)
117
+ self.commit_service = CommitServiceStub(self.channel)
118
+
119
+ def close(self):
120
+ self.channel.close()
121
+
122
+ def grpc_metadata(self):
123
+ mds = feature.as_grpc_metadata(self.feature_flags)
124
+ mds.append((SKIP_HOOKS_MD_KEY, 'true'))
125
+ mds.append((NATIVE_PROJECT_MD_KEY, 'true'))
126
+ return mds
127
+
128
+ def repo_exists(self, relpath):
129
+ return self.repository_service.RepositoryExists(
130
+ RepositoryExistsRequest(repository=gl_repo(relpath))
131
+ ).exists
132
+
133
+ def ensure_repos(self):
134
+ for relpath in self.repositories:
135
+ if self.repo_exists(relpath):
136
+ logger.info("Repository %r is present", relpath)
137
+ else:
138
+ self.import_repo(relpath)
139
+
140
+ def import_repo(self, relpath):
141
+ logger.warning("Importing repository %r", relpath)
142
+ self.repository_service.CreateRepository(
143
+ CreateRepositoryRequest(repository=gl_repo(relpath))
144
+ )
145
+
146
+ src_url = self.repositories[relpath]
147
+ self.hg_call(relpath,
148
+ (b"pull", b"-q",
149
+ b"--config", b"heptapod.initial-import=yes",
150
+ src_url.encode('ascii')),
151
+ timeout=3600)
152
+
153
+ def hg_call(self, relpath, args, timeout=30):
154
+ exit_code = -1
155
+ for resp in self.hg_repository_service.HgCall(
156
+ HgCallRequest(repository=gl_repo(relpath),
157
+ args=args),
158
+ metadata=self.grpc_metadata(),
159
+ timeout=timeout,
160
+ ):
161
+ exit_code = resp.exit_code
162
+ if exit_code != 0:
163
+ raise RuntimeError(f"HgCall exit code {exit_code}")
164
+
165
+ def run_one(self, name):
166
+ start = time.time()
167
+ try:
168
+ getattr(self, name)()
169
+ code = 'OK'
170
+ except grpc.RpcError as exc:
171
+ code = exc.code().name
172
+ if self.queue is None:
173
+ logger.error(
174
+ "Failed request when checking before actual load test"
175
+ )
176
+ raise
177
+
178
+ elapsed = time.time() - start
179
+
180
+ if self.queue is None:
181
+ logger.info("Ran %r in %d ms", name, elapsed * 1000)
182
+ else:
183
+ self.queue.put((name, code, elapsed), block=False, timeout=1)
184
+
185
+ def run_test(self, iterations):
186
+ for i in range(iterations):
187
+ meth = self.random_method()
188
+ logger.info("Iteration %d, running %r", i + 1, meth)
189
+ self.run_one(meth)
190
+
191
+ def sleep_a_bit(self):
192
+ # this can make RHGitaly find there are too many idle workers
193
+ # and recycle them, leading to interesting problems because of
194
+ # long HGitaly startup time.
195
+ time.sleep(2)
196
+
197
+ def find_commits_mercurial_devel(self):
198
+ count = 0
199
+ future = self.commit_service.FindCommits(FindCommitsRequest(
200
+ repository=gl_repo('mercurial-devel'),
201
+ revision=b'branch/default',
202
+ limit=100000,
203
+ paths=[b'rust/hg-core/Cargo.toml'],
204
+ ))
205
+
206
+ # see also `streaming_future_with_cancellation()`
207
+ for resp in future:
208
+ count += len(resp.commits)
209
+
210
+ logger.debug("Got FindCommits response with %d commits", count)
211
+
212
+ def count_commits_mercurial_devel(self):
213
+ resp = self.commit_service.CountCommits(CountCommitsRequest(
214
+ repository=gl_repo('mercurial-devel'),
215
+ revision=b'branch/default',
216
+ ))
217
+ logger.debug("Got FindCommits response with %d commits", resp.count)
218
+
219
+ def merge_analysis_mercurial_devel(self):
220
+ repo = gl_repo('mercurial-devel')
221
+ self.hg_operations_service.InvalidateMergeAnalysis(
222
+ InvalidateMergeAnalysisRequest(repository=repo)
223
+ )
224
+ # an actual merge, without conflicts
225
+ future = self.hg_operations_service.MergeAnalysis.future(
226
+ MergeAnalysisRequest(
227
+ repository=repo,
228
+ source_revision=b'412fd1f5d8bc',
229
+ target_revision=b'ff85442d08d7',
230
+ ),
231
+ timeout=120)
232
+ future.result() # see also unary_future_with_cancellation()
233
+
234
+ def assert_requests(self):
235
+ """Run all requiests exactly once.
236
+
237
+ If one of them fails (typically due to a programming mistake),
238
+ better to know it before running thousands of them
239
+ """
240
+ for (name, _w) in self.weighted_methods:
241
+ if name != 'sleep_a_bit':
242
+ self.run_one(name) # TODO check exit code
243
+
244
+
245
+ def cancel_in(future, ms):
246
+ time.sleep(ms / 1000)
247
+ logger.info("Client-side cancellation")
248
+ future.cancel()
249
+
250
+
251
+ def spawn_cancel_thread(*args):
252
+ t = threading.Thread(target=cancel_in, args=args)
253
+ t.start()
254
+ return t
255
+
256
+
257
+ def unary_future_with_cancellation(future, cancel_in_ms):
258
+ """Actually send the request, but cancel it first."""
259
+ t = spawn_cancel_thread(future, cancel_in_ms)
260
+ try:
261
+ return future.result()
262
+ finally:
263
+ t.join()
264
+
265
+
266
+ def streaming_future_with_cancellation(future, cancel_in_ms):
267
+ """Actually send the request, but cancel it first."""
268
+ t = spawn_cancel_thread(future, cancel_in_ms)
269
+ try:
270
+ for resp in future:
271
+ yield resp
272
+ finally:
273
+ t.join()
274
+
275
+
276
+ LoadWorker.compute_random_thresholds()
277
+ x = LoadWorker.random_method()
278
+ x = LoadWorker.random_method()
279
+ x = LoadWorker.random_method()
280
+
281
+
282
+ def worker(wid, url, queue, iterations):
283
+ worker = LoadWorker(url, queue, wid=wid)
284
+ worker.run_test(iterations)
285
+ queue.put(('DONE', wid))
286
+
287
+
288
+ def load_test():
289
+ parser = argparse.ArgumentParser(
290
+ formatter_class=argparse.ArgumentDefaultsHelpFormatter,
291
+ description=__doc__)
292
+
293
+ parser.add_argument('--url', '--rhgitaly-url',
294
+ help="URL of the RHGitaly server",
295
+ default='tcp://127.0.0.1:9237')
296
+ parser.add_argument('-c', '--concurrency', type=int, default=6)
297
+ parser.add_argument('--iterations', type=int, default=1000,
298
+ help="Number of iteration per client worker")
299
+ parser.add_argument('-l', '--logging-level', default='info')
300
+ cl_args = parser.parse_args()
301
+
302
+ logging.basicConfig(level=getattr(logging,
303
+ cl_args.logging_level.upper()))
304
+
305
+ concurrency = cl_args.concurrency
306
+
307
+ prepare_worker = LoadWorker(cl_args.url, queue=None)
308
+ prepare_worker.ensure_repos()
309
+ prepare_worker.assert_requests()
310
+ prepare_worker.close()
311
+
312
+ logger.warning("Preflight check of all requests passed. Proceeding to "
313
+ "actual load test")
314
+
315
+ queue = mp.Queue()
316
+
317
+ ctx = mp.get_context('fork')
318
+ processes = [ctx.Process(target=worker,
319
+ args=(i, cl_args.url, queue, cl_args.iterations))
320
+ for i in range(concurrency)]
321
+
322
+ for p in processes:
323
+ p.start()
324
+
325
+ done_process_ids = []
326
+ results = {}
327
+ while len(done_process_ids) < len(processes):
328
+ res = queue.get()
329
+ if res[0] == 'DONE':
330
+ wid = res[1]
331
+ processes[wid].join()
332
+ done_process_ids.append(wid)
333
+ logger.warning("Worker %d is done", wid)
334
+ else:
335
+ (results.setdefault(res[1], {})
336
+ .setdefault(res[0], [])
337
+ .append(res[2])
338
+ )
339
+
340
+ error_stats = {}
341
+ for code, details in results.items():
342
+ if code != 'OK':
343
+ for name, times in details.items():
344
+ error_stats.setdefault(name, {})[code] = dict(
345
+ count=len(times),
346
+ mean_time=statistics.mean(times)
347
+ )
348
+
349
+ successes = results.get('OK', {})
350
+ stats = {}
351
+ for name, times in successes.items():
352
+ mstats = stats[name] = dict(
353
+ count=len(times),
354
+ median=statistics.mean(times),
355
+ mean=statistics.median(times),
356
+ standard_deviation=statistics.pstdev(times),
357
+ )
358
+ if len(times) > 1:
359
+
360
+ deciles = statistics.quantiles(times, method='inclusive', n=10)
361
+ centiles = statistics.quantiles(times, method='inclusive',
362
+ n=100)
363
+ mstats["best_centile"] = centiles[0]
364
+ mstats["best_decile"] = deciles[0],
365
+ mstats["worst_centile"] = centiles[-1],
366
+ mstats["worst_decile"] = deciles[-1],
367
+
368
+ print(f"\n\nRESULTS for concurrency={concurrency}: ")
369
+ print(json.dumps(stats, indent=2))
370
+
371
+ if error_stats:
372
+ print(f"\n\nERRORS for concurrency={concurrency}: ")
373
+ print(json.dumps(error_stats, indent=2))
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.1
2
2
  Name: hgitaly
3
- Version: 18.7.1
3
+ Version: 18.7.2
4
4
  Summary: Server-side implementation of Gitaly protocol for Mercurial
5
5
  Home-page: https://foss.heptapod.net/heptapod/hgitaly
6
6
  Author: Georges Racinet
@@ -52,7 +52,6 @@ hgitaly/procutil.py
52
52
  hgitaly/repository.py
53
53
  hgitaly/revision.py
54
54
  hgitaly/revset.py
55
- hgitaly/scripts.py
56
55
  hgitaly/servicer.py
57
56
  hgitaly/ssh.py
58
57
  hgitaly/stream.py
@@ -65,6 +64,9 @@ hgitaly.egg-info/dependency_links.txt
65
64
  hgitaly.egg-info/entry_points.txt
66
65
  hgitaly.egg-info/requires.txt
67
66
  hgitaly.egg-info/top_level.txt
67
+ hgitaly/scripts/__init__.py
68
+ hgitaly/scripts/load_tests.py
69
+ hgitaly/scripts/stats.py
68
70
  hgitaly/server/__init__.py
69
71
  hgitaly/server/address.py
70
72
  hgitaly/server/mono.py
@@ -1,2 +1,3 @@
1
1
  [console_scripts]
2
+ hgitaly-load-test = hgitaly.scripts:load_test
2
3
  hgitaly-stats = hgitaly.scripts:stats
@@ -9,6 +9,7 @@ MAIN_PACKAGE = 'hgitaly'
9
9
 
10
10
  scripts = { # name to (module in main package, function)
11
11
  'hgitaly-stats': ('scripts', 'stats'),
12
+ 'hgitaly-load-test': ('scripts', 'load_test'),
12
13
  }
13
14
 
14
15
  setup(
@@ -1 +0,0 @@
1
- 18.7.1
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes