|
30 | 30 | import pytest |
31 | 31 |
|
32 | 32 | import pygit2 |
33 | | -from pygit2 import Remote, Repository |
| 33 | +from pygit2 import Remote, RemoteCallbacks, Repository |
| 34 | +from pygit2.ffi import ffi |
34 | 35 | from pygit2.remotes import PushUpdate, TransferProgress |
35 | 36 |
|
36 | 37 | from . import utils |
@@ -485,8 +486,6 @@ def test_push_non_fast_forward_commits_to_remote_fails( |
485 | 486 |
|
486 | 487 |
|
487 | 488 | def test_push_options(origin: Repository, clone: Repository, remote: Remote) -> None: |
488 | | - from pygit2 import RemoteCallbacks |
489 | | - |
490 | 489 | callbacks = RemoteCallbacks() |
491 | 490 | remote.push(['refs/heads/master'], callbacks) |
492 | 491 | remote_push_options = callbacks.push_options.remote_push_options |
@@ -515,8 +514,6 @@ def test_push_options(origin: Repository, clone: Repository, remote: Remote) -> |
515 | 514 |
|
516 | 515 |
|
517 | 516 | def test_push_threads(origin: Repository, clone: Repository, remote: Remote) -> None: |
518 | | - from pygit2 import RemoteCallbacks |
519 | | - |
520 | 517 | callbacks = RemoteCallbacks() |
521 | 518 | remote.push(['refs/heads/master'], callbacks) |
522 | 519 | assert callbacks.push_options.pb_parallelism == 1 |
@@ -562,3 +559,142 @@ def push_negotiation(self, updates: list[PushUpdate]) -> None: |
562 | 559 | assert the_updates[0].dst == new_tip_id |
563 | 560 |
|
564 | 561 | assert origin.branches['master'].target == new_tip_id |
| 562 | + |
| 563 | + |
| 564 | +class HeaderCallbacks(RemoteCallbacks): |
| 565 | + def custom_headers(self) -> list[str] | None: |
| 566 | + return ['X-Other-One: foo', 'X-Other-Two: bar'] |
| 567 | + |
| 568 | + |
| 569 | +def test_git_custom_headers_context_manager( |
| 570 | + origin: Repository, |
| 571 | + clone: Repository, |
| 572 | + remote: Remote, |
| 573 | +) -> None: |
| 574 | + from pygit2.callbacks import git_custom_headers, git_fetch_options, git_push_options |
| 575 | + |
| 576 | + class EmptyHeaderCallbacks(RemoteCallbacks): |
| 577 | + def custom_headers(self) -> list[str] | None: |
| 578 | + return [] |
| 579 | + |
| 580 | + callbacks = RemoteCallbacks() |
| 581 | + with git_custom_headers(callbacks) as headers: |
| 582 | + assert headers.ptr == ffi.NULL |
| 583 | + |
| 584 | + callbacks = EmptyHeaderCallbacks() |
| 585 | + with git_custom_headers(callbacks) as headers: |
| 586 | + assert headers.ptr == ffi.NULL |
| 587 | + |
| 588 | + callbacks = HeaderCallbacks() |
| 589 | + with git_custom_headers(callbacks) as headers: |
| 590 | + ptr = headers.ptr |
| 591 | + assert ptr != ffi.NULL |
| 592 | + assert ptr.count == 2 # type: ignore[union-attr] |
| 593 | + assert ffi.string(ptr.strings[0]) == b'X-Other-One: foo' # type: ignore[union-attr,index] |
| 594 | + assert ffi.string(ptr.strings[1]) == b'X-Other-Two: bar' # type: ignore[union-attr,index] |
| 595 | + |
| 596 | + callbacks = RemoteCallbacks() |
| 597 | + with git_fetch_options(callbacks) as payload: |
| 598 | + assert payload.fetch_options.custom_headers.count == 0 |
| 599 | + assert payload.fetch_options.custom_headers.strings == ffi.NULL |
| 600 | + |
| 601 | + callbacks = EmptyHeaderCallbacks() |
| 602 | + with git_fetch_options(callbacks) as payload: |
| 603 | + assert payload.fetch_options.custom_headers.count == 0 |
| 604 | + assert payload.fetch_options.custom_headers.strings == ffi.NULL |
| 605 | + |
| 606 | + callbacks = HeaderCallbacks() |
| 607 | + with git_fetch_options(callbacks) as payload: |
| 608 | + assert payload.fetch_options.custom_headers.count == 2 |
| 609 | + assert ( |
| 610 | + ffi.string(payload.fetch_options.custom_headers.strings[0]) |
| 611 | + == b'X-Other-One: foo' |
| 612 | + ) |
| 613 | + assert ( |
| 614 | + ffi.string(payload.fetch_options.custom_headers.strings[1]) |
| 615 | + == b'X-Other-Two: bar' |
| 616 | + ) |
| 617 | + |
| 618 | + callbacks = RemoteCallbacks() |
| 619 | + with git_push_options(callbacks) as payload: |
| 620 | + assert payload.push_options.custom_headers.count == 0 |
| 621 | + assert payload.push_options.custom_headers.strings == ffi.NULL |
| 622 | + |
| 623 | + callbacks = EmptyHeaderCallbacks() |
| 624 | + with git_push_options(callbacks) as payload: |
| 625 | + assert payload.push_options.custom_headers.count == 0 |
| 626 | + assert payload.push_options.custom_headers.strings == ffi.NULL |
| 627 | + |
| 628 | + callbacks = HeaderCallbacks() |
| 629 | + with git_push_options(callbacks) as payload: |
| 630 | + assert payload.push_options.custom_headers.count == 2 |
| 631 | + assert ( |
| 632 | + ffi.string(payload.push_options.custom_headers.strings[0]) |
| 633 | + == b'X-Other-One: foo' |
| 634 | + ) |
| 635 | + assert ( |
| 636 | + ffi.string(payload.push_options.custom_headers.strings[1]) |
| 637 | + == b'X-Other-Two: bar' |
| 638 | + ) |
| 639 | + |
| 640 | + |
| 641 | +def test_push_headers(origin: Repository, clone: Repository, remote: Remote) -> None: |
| 642 | + callbacks = RemoteCallbacks() |
| 643 | + remote.push(['refs/heads/master'], callbacks=callbacks) |
| 644 | + assert callbacks.push_options.custom_headers.count == 0 |
| 645 | + assert callbacks.push_options.custom_headers.strings == ffi.NULL |
| 646 | + |
| 647 | + callbacks = HeaderCallbacks() |
| 648 | + remote.push(['refs/heads/master'], callbacks=callbacks) |
| 649 | + assert callbacks.push_options.custom_headers.count == 2 |
| 650 | + assert callbacks.push_options.custom_headers.strings != ffi.NULL |
| 651 | + # strings pointed to by callbacks.push_options.custom_headers.strings[] are already freed |
| 652 | + |
| 653 | + # make sure the custom headers don't "stick around" |
| 654 | + callbacks = RemoteCallbacks() |
| 655 | + remote.push(['refs/heads/master'], callbacks=callbacks) |
| 656 | + assert callbacks.push_options.custom_headers.count == 0 |
| 657 | + assert callbacks.push_options.custom_headers.strings == ffi.NULL |
| 658 | + |
| 659 | + |
| 660 | +def test_fetch_headers(origin: Repository, clone: Repository, remote: Remote) -> None: |
| 661 | + callbacks = RemoteCallbacks() |
| 662 | + remote.fetch(['refs/heads/master'], callbacks=callbacks) |
| 663 | + assert callbacks.fetch_options.custom_headers.count == 0 |
| 664 | + assert callbacks.fetch_options.custom_headers.strings == ffi.NULL |
| 665 | + |
| 666 | + callbacks = HeaderCallbacks() |
| 667 | + remote.fetch(['refs/heads/master'], callbacks=callbacks) |
| 668 | + assert callbacks.fetch_options.custom_headers.count == 2 |
| 669 | + assert callbacks.fetch_options.custom_headers.strings != ffi.NULL |
| 670 | + # strings pointed to by callbacks.fetch_options.custom_headers.strings[] are already freed |
| 671 | + |
| 672 | + # make sure the custom headers don't "stick around" |
| 673 | + callbacks = RemoteCallbacks() |
| 674 | + remote.fetch(['refs/heads/master'], callbacks=callbacks) |
| 675 | + assert callbacks.fetch_options.custom_headers.count == 0 |
| 676 | + assert callbacks.fetch_options.custom_headers.strings == ffi.NULL |
| 677 | + |
| 678 | + |
| 679 | +@utils.requires_network |
| 680 | +def test_connect_headers(testrepo: Repository) -> None: |
| 681 | + # This is just a check that having custom headers doesn't cause errors. As far as I can tell, |
| 682 | + # there's no way to assert that C.git_remote_connect was called with the headers except for |
| 683 | + # having a remote server that expects the headers and fails without them. |
| 684 | + |
| 685 | + assert 1 == len(testrepo.remotes) |
| 686 | + remote = testrepo.remotes[0] |
| 687 | + |
| 688 | + callbacks = RemoteCallbacks() |
| 689 | + remote.connect(callbacks=callbacks) |
| 690 | + refs = remote.list_heads(connect=False) |
| 691 | + assert refs |
| 692 | + # Check that a known ref is returned. |
| 693 | + assert next(iter(r for r in refs if r.name == 'refs/tags/v0.28.2')) |
| 694 | + |
| 695 | + callbacks = HeaderCallbacks() |
| 696 | + remote.connect(callbacks=callbacks) |
| 697 | + refs = remote.list_heads(connect=False) |
| 698 | + assert refs |
| 699 | + # Check that a known ref is returned. |
| 700 | + assert next(iter(r for r in refs if r.name == 'refs/tags/v0.28.2')) |
0 commit comments