@@ -687,3 +687,213 @@ func TestPRCounts_TotalCalculation(t *testing.T) {
687687 })
688688 }
689689}
690+
691+ func TestGetBranchProtectionRulesCount (t * testing.T ) {
692+ viper .Set ("SOURCE_TOKEN" , "source-token" )
693+ viper .Set ("TARGET_TOKEN" , "target-token" )
694+
695+ tests := []struct {
696+ name string
697+ clientType ClientType
698+ owner string
699+ repo string
700+ wantError bool
701+ }{
702+ {
703+ name : "source client valid request" ,
704+ clientType : SourceClient ,
705+ owner : "testowner" ,
706+ repo : "testrepo" ,
707+ wantError : true , // Will error in test due to no real connection
708+ },
709+ {
710+ name : "target client valid request" ,
711+ clientType : TargetClient ,
712+ owner : "testowner" ,
713+ repo : "testrepo" ,
714+ wantError : true , // Will error in test due to no real connection
715+ },
716+ {
717+ name : "invalid client type" ,
718+ clientType : ClientType (999 ),
719+ owner : "testowner" ,
720+ repo : "testrepo" ,
721+ wantError : true ,
722+ },
723+ }
724+
725+ for _ , tt := range tests {
726+ t .Run (tt .name , func (t * testing.T ) {
727+ resetAPI ()
728+ api := GetAPI ()
729+
730+ count , err := api .GetBranchProtectionRulesCount (tt .clientType , tt .owner , tt .repo )
731+
732+ if (err != nil ) != tt .wantError {
733+ t .Errorf ("GetBranchProtectionRulesCount() error = %v, wantError %v" , err , tt .wantError )
734+ return
735+ }
736+
737+ if ! tt .wantError && count < 0 {
738+ t .Errorf ("GetBranchProtectionRulesCount() returned negative count: %d" , count )
739+ }
740+ })
741+ }
742+ }
743+
744+ func TestGitHubAPI_GetWebhookCount (t * testing.T ) {
745+ tests := []struct {
746+ name string
747+ clientType ClientType
748+ owner string
749+ repo string
750+ responseBody string
751+ expectedCount int
752+ expectedError bool
753+ }{
754+ {
755+ name : "successful webhook count - multiple webhooks" ,
756+ clientType : SourceClient ,
757+ owner : "testowner" ,
758+ repo : "testrepo" ,
759+ responseBody : `[
760+ {
761+ "id": 1,
762+ "name": "web",
763+ "active": true,
764+ "events": ["push", "pull_request"],
765+ "config": {
766+ "url": "https://example.com/webhook1",
767+ "content_type": "json"
768+ }
769+ },
770+ {
771+ "id": 2,
772+ "name": "web",
773+ "active": true,
774+ "events": ["issues"],
775+ "config": {
776+ "url": "https://example.com/webhook2",
777+ "content_type": "json"
778+ }
779+ }
780+ ]` ,
781+ expectedCount : 2 ,
782+ expectedError : false ,
783+ },
784+ {
785+ name : "no webhooks" ,
786+ clientType : TargetClient ,
787+ owner : "testowner" ,
788+ repo : "testrepo" ,
789+ responseBody : `[]` ,
790+ expectedCount : 0 ,
791+ expectedError : false ,
792+ },
793+ {
794+ name : "single webhook" ,
795+ clientType : SourceClient ,
796+ owner : "testowner" ,
797+ repo : "testrepo" ,
798+ responseBody : `[
799+ {
800+ "id": 1,
801+ "name": "web",
802+ "active": true,
803+ "events": ["push"],
804+ "config": {
805+ "url": "https://example.com/webhook",
806+ "content_type": "json"
807+ }
808+ }
809+ ]` ,
810+ expectedCount : 1 ,
811+ expectedError : false ,
812+ },
813+ {
814+ name : "mixed active and inactive webhooks - only counts active" ,
815+ clientType : SourceClient ,
816+ owner : "testowner" ,
817+ repo : "testrepo" ,
818+ responseBody : `[
819+ {
820+ "id": 1,
821+ "name": "web",
822+ "active": true,
823+ "events": ["push"],
824+ "config": {
825+ "url": "https://example.com/webhook1",
826+ "content_type": "json"
827+ }
828+ },
829+ {
830+ "id": 2,
831+ "name": "web",
832+ "active": false,
833+ "events": ["pull_request"],
834+ "config": {
835+ "url": "https://example.com/webhook2",
836+ "content_type": "json"
837+ }
838+ },
839+ {
840+ "id": 3,
841+ "name": "web",
842+ "active": true,
843+ "events": ["issues"],
844+ "config": {
845+ "url": "https://example.com/webhook3",
846+ "content_type": "json"
847+ }
848+ }
849+ ]` ,
850+ expectedCount : 2 ,
851+ expectedError : false ,
852+ },
853+ }
854+
855+ for _ , tt := range tests {
856+ t .Run (tt .name , func (t * testing.T ) {
857+ // Create mock transport that returns the test response
858+ mockTransport := & mockRoundTripper {
859+ roundTripFunc : func (req * http.Request ) (* http.Response , error ) {
860+ // Verify this is a webhook list request
861+ if ! strings .Contains (req .URL .Path , "/repos/" + tt .owner + "/" + tt .repo + "/hooks" ) {
862+ t .Errorf ("Expected webhook API endpoint, got: %s" , req .URL .Path )
863+ }
864+
865+ return & http.Response {
866+ StatusCode : 200 ,
867+ Body : io .NopCloser (strings .NewReader (tt .responseBody )),
868+ Header : make (http.Header ),
869+ }, nil
870+ },
871+ }
872+
873+ api := createTestAPI (mockTransport )
874+ count , err := api .GetWebhookCount (tt .clientType , tt .owner , tt .repo )
875+
876+ if tt .expectedError {
877+ if err == nil {
878+ t .Errorf ("Expected error, but got none" )
879+ }
880+ } else {
881+ if err != nil {
882+ t .Errorf ("Unexpected error: %v" , err )
883+ }
884+ if count != tt .expectedCount {
885+ t .Errorf ("Expected count %d, got %d" , tt .expectedCount , count )
886+ }
887+ }
888+ })
889+ }
890+ }
891+
892+ // mockRoundTripper implements http.RoundTripper for testing
893+ type mockRoundTripper struct {
894+ roundTripFunc func (req * http.Request ) (* http.Response , error )
895+ }
896+
897+ func (m * mockRoundTripper ) RoundTrip (req * http.Request ) (* http.Response , error ) {
898+ return m .roundTripFunc (req )
899+ }
0 commit comments