hgitaly 18.7.0a1__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.
- {hgitaly-18.7.0a1/hgitaly.egg-info → hgitaly-18.7.2}/PKG-INFO +2 -2
- {hgitaly-18.7.0a1 → hgitaly-18.7.2}/functional_tests/test_blob_tree.py +1 -1
- {hgitaly-18.7.0a1 → hgitaly-18.7.2}/functional_tests/test_commit.py +59 -8
- {hgitaly-18.7.0a1 → hgitaly-18.7.2}/functional_tests/test_ref.py +14 -0
- hgitaly-18.7.2/hgitaly/VERSION +1 -0
- {hgitaly-18.7.0a1 → hgitaly-18.7.2}/hgitaly/revset.py +9 -0
- hgitaly-18.7.2/hgitaly/scripts/__init__.py +3 -0
- hgitaly-18.7.2/hgitaly/scripts/load_tests.py +373 -0
- {hgitaly-18.7.0a1 → hgitaly-18.7.2}/hgitaly/service/commit.py +8 -0
- {hgitaly-18.7.0a1 → hgitaly-18.7.2}/hgitaly/service/tests/test_commit.py +12 -0
- {hgitaly-18.7.0a1 → hgitaly-18.7.2/hgitaly.egg-info}/PKG-INFO +2 -2
- {hgitaly-18.7.0a1 → hgitaly-18.7.2}/hgitaly.egg-info/SOURCES.txt +3 -1
- {hgitaly-18.7.0a1 → hgitaly-18.7.2}/hgitaly.egg-info/entry_points.txt +1 -0
- {hgitaly-18.7.0a1 → hgitaly-18.7.2}/hgitaly.egg-info/requires.txt +1 -1
- {hgitaly-18.7.0a1 → hgitaly-18.7.2}/install-requirements.txt +1 -1
- {hgitaly-18.7.0a1 → hgitaly-18.7.2}/setup.py +1 -0
- hgitaly-18.7.0a1/hgitaly/VERSION +0 -1
- {hgitaly-18.7.0a1 → hgitaly-18.7.2}/LICENSE +0 -0
- {hgitaly-18.7.0a1 → hgitaly-18.7.2}/MANIFEST.in +0 -0
- {hgitaly-18.7.0a1 → hgitaly-18.7.2}/README.md +0 -0
- {hgitaly-18.7.0a1 → hgitaly-18.7.2}/functional_tests/__init__.py +0 -0
- {hgitaly-18.7.0a1 → hgitaly-18.7.2}/functional_tests/comparison.py +0 -0
- {hgitaly-18.7.0a1 → hgitaly-18.7.2}/functional_tests/conftest.py +0 -0
- {hgitaly-18.7.0a1 → hgitaly-18.7.2}/functional_tests/gitaly.py +0 -0
- {hgitaly-18.7.0a1 → hgitaly-18.7.2}/functional_tests/hgitaly_rhgitaly_comparison.py +0 -0
- {hgitaly-18.7.0a1 → hgitaly-18.7.2}/functional_tests/rhgitaly.py +0 -0
- {hgitaly-18.7.0a1 → hgitaly-18.7.2}/functional_tests/test_comparison.py +0 -0
- {hgitaly-18.7.0a1 → hgitaly-18.7.2}/functional_tests/test_diff.py +0 -0
- {hgitaly-18.7.0a1 → hgitaly-18.7.2}/functional_tests/test_gitaly_server.py +0 -0
- {hgitaly-18.7.0a1 → hgitaly-18.7.2}/functional_tests/test_mercurial_aux_git.py +0 -0
- {hgitaly-18.7.0a1 → hgitaly-18.7.2}/functional_tests/test_mercurial_operations.py +0 -0
- {hgitaly-18.7.0a1 → hgitaly-18.7.2}/functional_tests/test_mercurial_repository.py +0 -0
- {hgitaly-18.7.0a1 → hgitaly-18.7.2}/functional_tests/test_operations.py +0 -0
- {hgitaly-18.7.0a1 → hgitaly-18.7.2}/functional_tests/test_remote.py +0 -0
- {hgitaly-18.7.0a1 → hgitaly-18.7.2}/functional_tests/test_repository_service.py +0 -0
- {hgitaly-18.7.0a1 → hgitaly-18.7.2}/functional_tests/test_rhgitaly_server.py +0 -0
- {hgitaly-18.7.0a1 → hgitaly-18.7.2}/functional_tests/test_server.py +0 -0
- {hgitaly-18.7.0a1 → hgitaly-18.7.2}/hgext3rd/__init__.py +0 -0
- {hgitaly-18.7.0a1 → hgitaly-18.7.2}/hgext3rd/hgitaly/__init__.py +0 -0
- {hgitaly-18.7.0a1 → hgitaly-18.7.2}/hgext3rd/hgitaly/revset.py +0 -0
- {hgitaly-18.7.0a1 → hgitaly-18.7.2}/hgext3rd/hgitaly/tests/__init__.py +0 -0
- {hgitaly-18.7.0a1 → hgitaly-18.7.2}/hgext3rd/hgitaly/tests/test_revset.py +0 -0
- {hgitaly-18.7.0a1 → hgitaly-18.7.2}/hgext3rd/hgitaly/tests/test_serve.py +0 -0
- {hgitaly-18.7.0a1 → hgitaly-18.7.2}/hgitaly/__init__.py +0 -0
- {hgitaly-18.7.0a1 → hgitaly-18.7.2}/hgitaly/branch.py +0 -0
- {hgitaly-18.7.0a1 → hgitaly-18.7.2}/hgitaly/changelog.py +0 -0
- {hgitaly-18.7.0a1 → hgitaly-18.7.2}/hgitaly/diff.py +0 -0
- {hgitaly-18.7.0a1 → hgitaly-18.7.2}/hgitaly/errors.py +0 -0
- {hgitaly-18.7.0a1 → hgitaly-18.7.2}/hgitaly/feature.py +0 -0
- {hgitaly-18.7.0a1 → hgitaly-18.7.2}/hgitaly/file_content.py +0 -0
- {hgitaly-18.7.0a1 → hgitaly-18.7.2}/hgitaly/file_context.py +0 -0
- {hgitaly-18.7.0a1 → hgitaly-18.7.2}/hgitaly/git.py +0 -0
- {hgitaly-18.7.0a1 → hgitaly-18.7.2}/hgitaly/gitlab_ref.py +0 -0
- {hgitaly-18.7.0a1 → hgitaly-18.7.2}/hgitaly/identification.py +0 -0
- {hgitaly-18.7.0a1 → hgitaly-18.7.2}/hgitaly/logging.py +0 -0
- {hgitaly-18.7.0a1 → hgitaly-18.7.2}/hgitaly/manifest.py +0 -0
- {hgitaly-18.7.0a1 → hgitaly-18.7.2}/hgitaly/message.py +0 -0
- {hgitaly-18.7.0a1 → hgitaly-18.7.2}/hgitaly/oid.py +0 -0
- {hgitaly-18.7.0a1 → hgitaly-18.7.2}/hgitaly/pagination.py +0 -0
- {hgitaly-18.7.0a1 → hgitaly-18.7.2}/hgitaly/path.py +0 -0
- {hgitaly-18.7.0a1 → hgitaly-18.7.2}/hgitaly/peer.py +0 -0
- {hgitaly-18.7.0a1 → hgitaly-18.7.2}/hgitaly/procutil.py +0 -0
- {hgitaly-18.7.0a1 → hgitaly-18.7.2}/hgitaly/repository.py +0 -0
- {hgitaly-18.7.0a1 → hgitaly-18.7.2}/hgitaly/revision.py +0 -0
- /hgitaly-18.7.0a1/hgitaly/scripts.py → /hgitaly-18.7.2/hgitaly/scripts/stats.py +0 -0
- {hgitaly-18.7.0a1 → hgitaly-18.7.2}/hgitaly/server/__init__.py +0 -0
- {hgitaly-18.7.0a1 → hgitaly-18.7.2}/hgitaly/server/address.py +0 -0
- {hgitaly-18.7.0a1 → hgitaly-18.7.2}/hgitaly/server/mono.py +0 -0
- {hgitaly-18.7.0a1 → hgitaly-18.7.2}/hgitaly/server/tests/__init__.py +0 -0
- {hgitaly-18.7.0a1 → hgitaly-18.7.2}/hgitaly/server/tests/test_address.py +0 -0
- {hgitaly-18.7.0a1 → hgitaly-18.7.2}/hgitaly/server/tests/test_mono.py +0 -0
- {hgitaly-18.7.0a1 → hgitaly-18.7.2}/hgitaly/server/tests/test_worker.py +0 -0
- {hgitaly-18.7.0a1 → hgitaly-18.7.2}/hgitaly/server/worker.py +0 -0
- {hgitaly-18.7.0a1 → hgitaly-18.7.2}/hgitaly/service/__init__.py +0 -0
- {hgitaly-18.7.0a1 → hgitaly-18.7.2}/hgitaly/service/analysis.py +0 -0
- {hgitaly-18.7.0a1 → hgitaly-18.7.2}/hgitaly/service/blob.py +0 -0
- {hgitaly-18.7.0a1 → hgitaly-18.7.2}/hgitaly/service/diff.py +0 -0
- {hgitaly-18.7.0a1 → hgitaly-18.7.2}/hgitaly/service/interceptors.py +0 -0
- {hgitaly-18.7.0a1 → hgitaly-18.7.2}/hgitaly/service/mercurial_changeset.py +0 -0
- {hgitaly-18.7.0a1 → hgitaly-18.7.2}/hgitaly/service/mercurial_namespace.py +0 -0
- {hgitaly-18.7.0a1 → hgitaly-18.7.2}/hgitaly/service/mercurial_operations.py +0 -0
- {hgitaly-18.7.0a1 → hgitaly-18.7.2}/hgitaly/service/mercurial_repository.py +0 -0
- {hgitaly-18.7.0a1 → hgitaly-18.7.2}/hgitaly/service/operations.py +0 -0
- {hgitaly-18.7.0a1 → hgitaly-18.7.2}/hgitaly/service/ref.py +0 -0
- {hgitaly-18.7.0a1 → hgitaly-18.7.2}/hgitaly/service/repository.py +0 -0
- {hgitaly-18.7.0a1 → hgitaly-18.7.2}/hgitaly/service/server.py +0 -0
- {hgitaly-18.7.0a1 → hgitaly-18.7.2}/hgitaly/service/tests/__init__.py +0 -0
- {hgitaly-18.7.0a1 → hgitaly-18.7.2}/hgitaly/service/tests/fixture.py +0 -0
- {hgitaly-18.7.0a1 → hgitaly-18.7.2}/hgitaly/service/tests/test_analysis.py +0 -0
- {hgitaly-18.7.0a1 → hgitaly-18.7.2}/hgitaly/service/tests/test_blob.py +0 -0
- {hgitaly-18.7.0a1 → hgitaly-18.7.2}/hgitaly/service/tests/test_default_branch.py +0 -0
- {hgitaly-18.7.0a1 → hgitaly-18.7.2}/hgitaly/service/tests/test_diff.py +0 -0
- {hgitaly-18.7.0a1 → hgitaly-18.7.2}/hgitaly/service/tests/test_mercurial_changeset.py +0 -0
- {hgitaly-18.7.0a1 → hgitaly-18.7.2}/hgitaly/service/tests/test_mercurial_namespace.py +0 -0
- {hgitaly-18.7.0a1 → hgitaly-18.7.2}/hgitaly/service/tests/test_mercurial_operations.py +0 -0
- {hgitaly-18.7.0a1 → hgitaly-18.7.2}/hgitaly/service/tests/test_mercurial_repository.py +0 -0
- {hgitaly-18.7.0a1 → hgitaly-18.7.2}/hgitaly/service/tests/test_operations.py +0 -0
- {hgitaly-18.7.0a1 → hgitaly-18.7.2}/hgitaly/service/tests/test_ref.py +0 -0
- {hgitaly-18.7.0a1 → hgitaly-18.7.2}/hgitaly/service/tests/test_repository_service.py +0 -0
- {hgitaly-18.7.0a1 → hgitaly-18.7.2}/hgitaly/service/tests/test_server.py +0 -0
- {hgitaly-18.7.0a1 → hgitaly-18.7.2}/hgitaly/servicer.py +0 -0
- {hgitaly-18.7.0a1 → hgitaly-18.7.2}/hgitaly/ssh.py +0 -0
- {hgitaly-18.7.0a1 → hgitaly-18.7.2}/hgitaly/stream.py +0 -0
- {hgitaly-18.7.0a1 → hgitaly-18.7.2}/hgitaly/stub/__init__.py +0 -0
- {hgitaly-18.7.0a1 → hgitaly-18.7.2}/hgitaly/stub/analysis_pb2.py +0 -0
- {hgitaly-18.7.0a1 → hgitaly-18.7.2}/hgitaly/stub/analysis_pb2_grpc.py +0 -0
- {hgitaly-18.7.0a1 → hgitaly-18.7.2}/hgitaly/stub/blob_pb2.py +0 -0
- {hgitaly-18.7.0a1 → hgitaly-18.7.2}/hgitaly/stub/blob_pb2_grpc.py +0 -0
- {hgitaly-18.7.0a1 → hgitaly-18.7.2}/hgitaly/stub/commit_pb2.py +0 -0
- {hgitaly-18.7.0a1 → hgitaly-18.7.2}/hgitaly/stub/commit_pb2_grpc.py +0 -0
- {hgitaly-18.7.0a1 → hgitaly-18.7.2}/hgitaly/stub/diff_pb2.py +0 -0
- {hgitaly-18.7.0a1 → hgitaly-18.7.2}/hgitaly/stub/diff_pb2_grpc.py +0 -0
- {hgitaly-18.7.0a1 → hgitaly-18.7.2}/hgitaly/stub/errors_pb2.py +0 -0
- {hgitaly-18.7.0a1 → hgitaly-18.7.2}/hgitaly/stub/errors_pb2_grpc.py +0 -0
- {hgitaly-18.7.0a1 → hgitaly-18.7.2}/hgitaly/stub/lint_pb2.py +0 -0
- {hgitaly-18.7.0a1 → hgitaly-18.7.2}/hgitaly/stub/lint_pb2_grpc.py +0 -0
- {hgitaly-18.7.0a1 → hgitaly-18.7.2}/hgitaly/stub/mercurial_aux_git_pb2.py +0 -0
- {hgitaly-18.7.0a1 → hgitaly-18.7.2}/hgitaly/stub/mercurial_aux_git_pb2_grpc.py +0 -0
- {hgitaly-18.7.0a1 → hgitaly-18.7.2}/hgitaly/stub/mercurial_changeset_pb2.py +0 -0
- {hgitaly-18.7.0a1 → hgitaly-18.7.2}/hgitaly/stub/mercurial_changeset_pb2_grpc.py +0 -0
- {hgitaly-18.7.0a1 → hgitaly-18.7.2}/hgitaly/stub/mercurial_namespace_pb2.py +0 -0
- {hgitaly-18.7.0a1 → hgitaly-18.7.2}/hgitaly/stub/mercurial_namespace_pb2_grpc.py +0 -0
- {hgitaly-18.7.0a1 → hgitaly-18.7.2}/hgitaly/stub/mercurial_operations_pb2.py +0 -0
- {hgitaly-18.7.0a1 → hgitaly-18.7.2}/hgitaly/stub/mercurial_operations_pb2_grpc.py +0 -0
- {hgitaly-18.7.0a1 → hgitaly-18.7.2}/hgitaly/stub/mercurial_repository_pb2.py +0 -0
- {hgitaly-18.7.0a1 → hgitaly-18.7.2}/hgitaly/stub/mercurial_repository_pb2_grpc.py +0 -0
- {hgitaly-18.7.0a1 → hgitaly-18.7.2}/hgitaly/stub/operations_pb2.py +0 -0
- {hgitaly-18.7.0a1 → hgitaly-18.7.2}/hgitaly/stub/operations_pb2_grpc.py +0 -0
- {hgitaly-18.7.0a1 → hgitaly-18.7.2}/hgitaly/stub/ref_pb2.py +0 -0
- {hgitaly-18.7.0a1 → hgitaly-18.7.2}/hgitaly/stub/ref_pb2_grpc.py +0 -0
- {hgitaly-18.7.0a1 → hgitaly-18.7.2}/hgitaly/stub/remote_pb2.py +0 -0
- {hgitaly-18.7.0a1 → hgitaly-18.7.2}/hgitaly/stub/remote_pb2_grpc.py +0 -0
- {hgitaly-18.7.0a1 → hgitaly-18.7.2}/hgitaly/stub/repository_pb2.py +0 -0
- {hgitaly-18.7.0a1 → hgitaly-18.7.2}/hgitaly/stub/repository_pb2_grpc.py +0 -0
- {hgitaly-18.7.0a1 → hgitaly-18.7.2}/hgitaly/stub/server_pb2.py +0 -0
- {hgitaly-18.7.0a1 → hgitaly-18.7.2}/hgitaly/stub/server_pb2_grpc.py +0 -0
- {hgitaly-18.7.0a1 → hgitaly-18.7.2}/hgitaly/stub/shared_pb2.py +0 -0
- {hgitaly-18.7.0a1 → hgitaly-18.7.2}/hgitaly/stub/shared_pb2_grpc.py +0 -0
- {hgitaly-18.7.0a1 → hgitaly-18.7.2}/hgitaly/tag.py +0 -0
- {hgitaly-18.7.0a1 → hgitaly-18.7.2}/hgitaly/testing/__init__.py +0 -0
- {hgitaly-18.7.0a1 → hgitaly-18.7.2}/hgitaly/testing/bundle.py +0 -0
- {hgitaly-18.7.0a1 → hgitaly-18.7.2}/hgitaly/testing/context.py +0 -0
- {hgitaly-18.7.0a1 → hgitaly-18.7.2}/hgitaly/testing/grpc.py +0 -0
- {hgitaly-18.7.0a1 → hgitaly-18.7.2}/hgitaly/testing/multiprocessing.py +0 -0
- {hgitaly-18.7.0a1 → hgitaly-18.7.2}/hgitaly/testing/repo.py +0 -0
- {hgitaly-18.7.0a1 → hgitaly-18.7.2}/hgitaly/testing/ssh.py +0 -0
- {hgitaly-18.7.0a1 → hgitaly-18.7.2}/hgitaly/testing/sshd.py +0 -0
- {hgitaly-18.7.0a1 → hgitaly-18.7.2}/hgitaly/testing/storage.py +0 -0
- {hgitaly-18.7.0a1 → hgitaly-18.7.2}/hgitaly/testing/tests/__init__.py +0 -0
- {hgitaly-18.7.0a1 → hgitaly-18.7.2}/hgitaly/testing/tests/test_sshd.py +0 -0
- {hgitaly-18.7.0a1 → hgitaly-18.7.2}/hgitaly/tests/__init__.py +0 -0
- {hgitaly-18.7.0a1 → hgitaly-18.7.2}/hgitaly/tests/common.py +0 -0
- {hgitaly-18.7.0a1 → hgitaly-18.7.2}/hgitaly/tests/test_branch.py +0 -0
- {hgitaly-18.7.0a1 → hgitaly-18.7.2}/hgitaly/tests/test_diff.py +0 -0
- {hgitaly-18.7.0a1 → hgitaly-18.7.2}/hgitaly/tests/test_errors.py +0 -0
- {hgitaly-18.7.0a1 → hgitaly-18.7.2}/hgitaly/tests/test_feature.py +0 -0
- {hgitaly-18.7.0a1 → hgitaly-18.7.2}/hgitaly/tests/test_file_context.py +0 -0
- {hgitaly-18.7.0a1 → hgitaly-18.7.2}/hgitaly/tests/test_gitlab_ref.py +0 -0
- {hgitaly-18.7.0a1 → hgitaly-18.7.2}/hgitaly/tests/test_identification.py +0 -0
- {hgitaly-18.7.0a1 → hgitaly-18.7.2}/hgitaly/tests/test_manifest.py +0 -0
- {hgitaly-18.7.0a1 → hgitaly-18.7.2}/hgitaly/tests/test_messages.py +0 -0
- {hgitaly-18.7.0a1 → hgitaly-18.7.2}/hgitaly/tests/test_oid.py +0 -0
- {hgitaly-18.7.0a1 → hgitaly-18.7.2}/hgitaly/tests/test_peer.py +0 -0
- {hgitaly-18.7.0a1 → hgitaly-18.7.2}/hgitaly/tests/test_repository.py +0 -0
- {hgitaly-18.7.0a1 → hgitaly-18.7.2}/hgitaly/tests/test_revision.py +0 -0
- {hgitaly-18.7.0a1 → hgitaly-18.7.2}/hgitaly/tests/test_revset.py +0 -0
- {hgitaly-18.7.0a1 → hgitaly-18.7.2}/hgitaly/tests/test_servicer.py +0 -0
- {hgitaly-18.7.0a1 → hgitaly-18.7.2}/hgitaly/tests/test_stream.py +0 -0
- {hgitaly-18.7.0a1 → hgitaly-18.7.2}/hgitaly/tests/test_tag.py +0 -0
- {hgitaly-18.7.0a1 → hgitaly-18.7.2}/hgitaly/tests/test_workdir.py +0 -0
- {hgitaly-18.7.0a1 → hgitaly-18.7.2}/hgitaly/util.py +0 -0
- {hgitaly-18.7.0a1 → hgitaly-18.7.2}/hgitaly/workdir.py +0 -0
- {hgitaly-18.7.0a1 → hgitaly-18.7.2}/hgitaly.egg-info/dependency_links.txt +0 -0
- {hgitaly-18.7.0a1 → hgitaly-18.7.2}/hgitaly.egg-info/top_level.txt +0 -0
- {hgitaly-18.7.0a1 → 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.
|
|
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
|
|
@@ -10,7 +10,7 @@ Keywords: hg mercurial heptapod gitlab
|
|
|
10
10
|
Requires-Python: >=3.8
|
|
11
11
|
Description-Content-Type: text/markdown
|
|
12
12
|
License-File: LICENSE
|
|
13
|
-
Requires-Dist: heptapod
|
|
13
|
+
Requires-Dist: heptapod~=5.5.0
|
|
14
14
|
Requires-Dist: protobuf~=6.31.1
|
|
15
15
|
Requires-Dist: grpcio~=1.76.0
|
|
16
16
|
Requires-Dist: grpcio-status~=1.76.0
|
|
@@ -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
|
-
|
|
415
|
+
)
|
|
416
416
|
|
|
417
417
|
# case of no pagination params
|
|
418
418
|
assert_compare_aggregated(path=b'sub',
|
|
@@ -17,6 +17,7 @@ from hgitaly.stub.shared_pb2 import (
|
|
|
17
17
|
from hgitaly.stub.commit_pb2 import (
|
|
18
18
|
CommitLanguagesRequest,
|
|
19
19
|
CommitIsAncestorRequest,
|
|
20
|
+
CountCommitsRequest,
|
|
20
21
|
FindCommitRequest,
|
|
21
22
|
FindCommitsRequest,
|
|
22
23
|
LastCommitForPathRequest,
|
|
@@ -40,6 +41,8 @@ if skip_comparison_tests(): # pragma no cover
|
|
|
40
41
|
|
|
41
42
|
parametrize = pytest.mark.parametrize
|
|
42
43
|
|
|
44
|
+
PSEUDO_RANGE_SEPARATORS = (b'..', b'...')
|
|
45
|
+
|
|
43
46
|
|
|
44
47
|
def test_compare_last_commit_for(gitaly_rhgitaly_comparison):
|
|
45
48
|
fixture = gitaly_rhgitaly_comparison
|
|
@@ -583,14 +586,20 @@ def test_compare_count_find_commits(gitaly_rhgitaly_comparison, hg_server):
|
|
|
583
586
|
wrapper.update(2)
|
|
584
587
|
ctx4 = wrapper.merge_commit(ctx3, message=b'merge with stable',
|
|
585
588
|
utc_timestamp=ts+20)
|
|
589
|
+
unknown = b'unknown'
|
|
590
|
+
unknown_sha = b'cade12fe' * 5
|
|
591
|
+
range_with_unknown = b'..'.join((unknown_sha, ctx2.hex()))
|
|
592
|
+
assert_compare_errors(revision=unknown)
|
|
593
|
+
assert_compare_errors(revision=unknown_sha)
|
|
594
|
+
assert_compare_errors(revision=range_with_unknown)
|
|
586
595
|
|
|
587
596
|
# when `revision` is provided as <revspec>
|
|
588
597
|
with sorted_comparison():
|
|
589
598
|
all_revs = [ctx0.hex(), ctx1.hex(), ctx2.hex(), ctx3.hex(), ctx4.hex()]
|
|
590
|
-
for
|
|
599
|
+
for range_sep in PSEUDO_RANGE_SEPARATORS:
|
|
591
600
|
for r1 in all_revs:
|
|
592
601
|
for r2 in all_revs:
|
|
593
|
-
assert_compare(revision=r1 +
|
|
602
|
+
assert_compare(revision=r1 + range_sep + r2)
|
|
594
603
|
|
|
595
604
|
# with message_regex
|
|
596
605
|
rx = 'FOO.*zoO' # tests case insensitivity
|
|
@@ -688,7 +697,7 @@ def test_compare_count_find_commits(gitaly_rhgitaly_comparison, hg_server):
|
|
|
688
697
|
hg_server=hg_server,
|
|
689
698
|
stub_cls=CommitServiceStub,
|
|
690
699
|
method_name='CountCommits',
|
|
691
|
-
request_cls=
|
|
700
|
+
request_cls=CountCommitsRequest,
|
|
692
701
|
request_sha_attrs=['revision'],
|
|
693
702
|
)
|
|
694
703
|
|
|
@@ -697,7 +706,10 @@ def test_compare_count_find_commits(gitaly_rhgitaly_comparison, hg_server):
|
|
|
697
706
|
|
|
698
707
|
# when `revision` is provided as <revspec>
|
|
699
708
|
all_revs = [ctx0.hex(), ctx1.hex(), ctx2.hex(), ctx3.hex(), ctx4.hex()]
|
|
700
|
-
|
|
709
|
+
range_ops = [b'..']
|
|
710
|
+
if hg_server == 'rhgitaly':
|
|
711
|
+
range_ops.append(b'...')
|
|
712
|
+
for range_str in range_ops:
|
|
701
713
|
for r1 in all_revs:
|
|
702
714
|
for r2 in all_revs:
|
|
703
715
|
assert_compare(revision=r1 + range_str + r2)
|
|
@@ -708,11 +720,27 @@ def test_compare_count_find_commits(gitaly_rhgitaly_comparison, hg_server):
|
|
|
708
720
|
for ref in refs:
|
|
709
721
|
rpc_helper.assert_compare(revision=ref)
|
|
710
722
|
|
|
723
|
+
for mc in (0, 1, 2, 3):
|
|
724
|
+
assert_compare(revision=ctx2.hex(), max_count=mc)
|
|
725
|
+
|
|
726
|
+
assert_compare(all=True)
|
|
727
|
+
|
|
728
|
+
if hg_server == 'rhgitaly':
|
|
729
|
+
for date in [date1, date2]:
|
|
730
|
+
assert_compare(revision=ctx4.hex(), after=date)
|
|
731
|
+
assert_compare(revision=ctx4.hex(), before=date)
|
|
732
|
+
assert_compare(revision=ctx4.hex(), before=date, after=date)
|
|
733
|
+
assert_compare(revision=ctx4.hex(), before=date1, after=date2)
|
|
734
|
+
|
|
711
735
|
assert_compare_errors()
|
|
736
|
+
assert_compare(revision=unknown)
|
|
737
|
+
assert_compare(revision=unknown_sha)
|
|
738
|
+
assert_compare(revision=range_with_unknown)
|
|
712
739
|
|
|
713
740
|
|
|
714
|
-
|
|
715
|
-
|
|
741
|
+
@parametrize('hg_server', ('hgitaly', 'rhgitaly'))
|
|
742
|
+
def test_compare_list_commits(gitaly_rhgitaly_comparison, hg_server):
|
|
743
|
+
fixture = gitaly_rhgitaly_comparison
|
|
716
744
|
|
|
717
745
|
wrapper = fixture.hg_repo_wrapper
|
|
718
746
|
# set_default_gitlab_branch(wrapper.repo, b'branch/default')
|
|
@@ -720,7 +748,7 @@ def test_compare_list_commits(gitaly_comparison):
|
|
|
720
748
|
#
|
|
721
749
|
# @ 4 (branch/default) merge with stable
|
|
722
750
|
# |\
|
|
723
|
-
# | o 3 creates '
|
|
751
|
+
# | o 3 creates 'animals' (branch/stable)
|
|
724
752
|
# | |
|
|
725
753
|
# o | 2 rename 'foo' to 'zoo' (user: testuser)
|
|
726
754
|
# |/
|
|
@@ -741,9 +769,12 @@ def test_compare_list_commits(gitaly_comparison):
|
|
|
741
769
|
ctx2 = wrapper.commit([b'foo', b'zoo'],
|
|
742
770
|
message=b"rename foo to zoo",
|
|
743
771
|
utc_timestamp=ts - 10)
|
|
772
|
+
# TODO the converted email by hg-git is more liberal, and would
|
|
773
|
+
# parse the email correctly from 'testuser <testuser@heptapod.test'.
|
|
774
|
+
# Same with HGitaly, compared to RHGitaly.
|
|
744
775
|
ctx3 = wrapper.write_commit('animals', branch='stable', parent=ctx0,
|
|
745
776
|
utc_timestamp=ts + 10,
|
|
746
|
-
user='testuser <testuser@heptapod.test')
|
|
777
|
+
user='testuser <testuser@heptapod.test>')
|
|
747
778
|
wrapper.update(2)
|
|
748
779
|
ctx4 = wrapper.merge_commit(ctx3, message=b'merge with stable',
|
|
749
780
|
utc_timestamp=ts+20)
|
|
@@ -754,6 +785,7 @@ def test_compare_list_commits(gitaly_comparison):
|
|
|
754
785
|
normalize_commit_message(commit)
|
|
755
786
|
|
|
756
787
|
rpc_helper = fixture.rpc_helper(
|
|
788
|
+
hg_server=hg_server,
|
|
757
789
|
stub_cls=CommitServiceStub,
|
|
758
790
|
method_name='ListCommits',
|
|
759
791
|
request_cls=ListCommitsRequest,
|
|
@@ -805,12 +837,31 @@ def test_compare_list_commits(gitaly_comparison):
|
|
|
805
837
|
|
|
806
838
|
assert_compare(revisions=[ctx4.hex(), caret(ctx1)])
|
|
807
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
|
+
|
|
808
847
|
# interpretation of several exclusions
|
|
809
848
|
assert_compare(revisions=[ctx4.hex(), caret(ctx1), caret(ctx2)])
|
|
810
849
|
|
|
811
850
|
# no result
|
|
812
851
|
assert_compare(revisions=[ctx4.hex(), caret(ctx4)])
|
|
813
852
|
|
|
853
|
+
# with paths
|
|
854
|
+
assert_compare(revisions=[ctx4.hex()], paths=[b'animals'])
|
|
855
|
+
assert_compare(revisions=[ctx4.hex()], paths=[b'foo'])
|
|
856
|
+
assert_compare(revisions=[ctx4.hex()], paths=[b'zoo'])
|
|
857
|
+
assert_compare(revisions=[ctx3.hex(), ctx2.hex()],
|
|
858
|
+
paths=[b'animals', b'zoo'])
|
|
859
|
+
assert_compare(revisions=[ctx4.hex()], paths=[b'anim*'])
|
|
860
|
+
# with two paths, Git starts returning the merge
|
|
861
|
+
# but Mercurial does not. This seems more consistent on the Mercurial
|
|
862
|
+
# side, so we won't compare. It would be:
|
|
863
|
+
# assert_compare(revisions=[ctx4.hex()], paths=[b'anim*', b'foo'])
|
|
864
|
+
|
|
814
865
|
# orderings
|
|
815
866
|
#
|
|
816
867
|
# Comparison is limited because Mercurial orderings don't exactly
|
|
@@ -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
|
|
@@ -60,6 +60,9 @@ def revset_from_git_revspec(repo, revspec, for_follow=False):
|
|
|
60
60
|
return None
|
|
61
61
|
return ctx.hex() if for_follow else b"reverse(::%s)" % ctx
|
|
62
62
|
|
|
63
|
+
if revset is None:
|
|
64
|
+
return None
|
|
65
|
+
|
|
63
66
|
return b"sort(%s, -rev)" % revset
|
|
64
67
|
|
|
65
68
|
|
|
@@ -90,6 +93,9 @@ def revset_git_range(repo, r1, r2, for_follow=False):
|
|
|
90
93
|
raise FollowNotImplemented()
|
|
91
94
|
|
|
92
95
|
ctx_start, ctx_end = resolve_git_range(repo, r1, r2)
|
|
96
|
+
if ctx_start is None or ctx_end is None:
|
|
97
|
+
return None
|
|
98
|
+
|
|
93
99
|
return b"::%s - ::%s" % (ctx_end, ctx_start)
|
|
94
100
|
|
|
95
101
|
|
|
@@ -114,6 +120,9 @@ def revset_symmetric_difference(repo, r1, r2, for_follow=False):
|
|
|
114
120
|
raise FollowNotImplemented()
|
|
115
121
|
|
|
116
122
|
ctx_start, ctx_end = resolve_git_range(repo, r1, r2)
|
|
123
|
+
if ctx_start is None or ctx_end is None:
|
|
124
|
+
return None
|
|
125
|
+
|
|
117
126
|
left = ctx_start.rev()
|
|
118
127
|
right = ctx_end.rev()
|
|
119
128
|
branchpoint = repo.revs(b"ancestor(%d, %d)" % (left, right)).first()
|
|
@@ -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))
|
|
@@ -559,6 +559,14 @@ class CommitServicer(CommitServiceServicer, HGitalyServicer):
|
|
|
559
559
|
if request.max_parents == 1:
|
|
560
560
|
revset += b" and not merge()"
|
|
561
561
|
|
|
562
|
+
if request.paths:
|
|
563
|
+
revset += b" and ("
|
|
564
|
+
revset += b" or ".join(
|
|
565
|
+
b'file("%s/%s")' % (repo.root, p)
|
|
566
|
+
for p in request.paths
|
|
567
|
+
)
|
|
568
|
+
revset += b")"
|
|
569
|
+
|
|
562
570
|
Order = ListCommitsRequest.Order
|
|
563
571
|
reverse = request.reverse
|
|
564
572
|
|
|
@@ -223,6 +223,11 @@ def test_find_commits(commit_fixture_empty_repo):
|
|
|
223
223
|
# when revision does not exists (including special Node IDs)
|
|
224
224
|
for rev in (b'does_not_exists',
|
|
225
225
|
b'1234deadbeaf',
|
|
226
|
+
b'1234dead' * 5,
|
|
227
|
+
b'unknown..%s' % ctx1.hex(),
|
|
228
|
+
b'%s..unknown' % ctx1.hex(),
|
|
229
|
+
b'unknown...%s' % ctx1.hex(),
|
|
230
|
+
b'%s...unknown' % ctx1.hex(),
|
|
226
231
|
b'ffffffff' * 5,
|
|
227
232
|
b'ffffffff'):
|
|
228
233
|
with pytest.raises(grpc.RpcError) as exc_info:
|
|
@@ -805,6 +810,13 @@ def test_list_commits(commit_fixture_empty_repo):
|
|
|
805
810
|
# author regexp
|
|
806
811
|
assert list_commits(sha4, author=b't.stuser') == [sha3]
|
|
807
812
|
|
|
813
|
+
# paths
|
|
814
|
+
assert list_commits(sha4, paths=[b'animals']) == [sha3]
|
|
815
|
+
assert list_commits(sha4, paths=[b'anim*']) == [sha3]
|
|
816
|
+
# Mercurial does not count the merge (see also comment in Comp test)
|
|
817
|
+
assert list_commits(sha4,
|
|
818
|
+
paths=[b'foo', b'animals']) == [sha3, sha2, sha0]
|
|
819
|
+
|
|
808
820
|
# unknown revision, including special cases:
|
|
809
821
|
for unknown in ('branch/unknown',
|
|
810
822
|
'f' * 39, # wdir node id, prefix
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.1
|
|
2
2
|
Name: hgitaly
|
|
3
|
-
Version: 18.7.
|
|
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
|
|
@@ -10,7 +10,7 @@ Keywords: hg mercurial heptapod gitlab
|
|
|
10
10
|
Requires-Python: >=3.8
|
|
11
11
|
Description-Content-Type: text/markdown
|
|
12
12
|
License-File: LICENSE
|
|
13
|
-
Requires-Dist: heptapod
|
|
13
|
+
Requires-Dist: heptapod~=5.5.0
|
|
14
14
|
Requires-Dist: protobuf~=6.31.1
|
|
15
15
|
Requires-Dist: grpcio~=1.76.0
|
|
16
16
|
Requires-Dist: grpcio-status~=1.76.0
|