88import hudson .security .AccessControlled ;
99import hudson .util .StreamTaskListener ;
1010import io .jenkins .plugins .gitlabbranchsource .helpers .GitLabHelper ;
11+ import io .jenkins .plugins .gitlabbranchsource .helpers .Sleeper ;
1112import io .jenkins .plugins .gitlabserverconfig .servers .GitLabServer ;
1213import io .jenkins .plugins .gitlabserverconfig .servers .GitLabServers ;
1314import java .io .ByteArrayOutputStream ;
1415import java .io .IOException ;
1516import java .nio .charset .StandardCharsets ;
1617import java .util .Arrays ;
18+ import java .util .List ;
19+ import java .util .Map ;
1720import java .util .Set ;
21+ import java .util .concurrent .atomic .AtomicInteger ;
1822import jenkins .branch .BranchSource ;
1923import jenkins .scm .api .SCMHead ;
24+ import jenkins .scm .api .SCMSourceOwner ;
2025import org .gitlab4j .api .GitLabApi ;
2126import org .gitlab4j .api .GitLabApiException ;
2227import org .gitlab4j .api .MergeRequestApi ;
2328import org .gitlab4j .api .ProjectApi ;
2429import org .gitlab4j .api .RepositoryApi ;
30+ import org .gitlab4j .api .models .AccessLevel ;
31+ import org .gitlab4j .api .models .Member ;
2532import org .gitlab4j .api .models .Project ;
2633import org .jenkinsci .plugins .workflow .multibranch .WorkflowMultiBranchProject ;
34+ import org .junit .After ;
35+ import org .junit .Before ;
2736import org .junit .ClassRule ;
2837import org .junit .Test ;
2938import org .jvnet .hudson .test .JenkinsRule ;
39+ import org .mockito .MockedConstruction ;
3040import org .mockito .MockedStatic ;
3141import org .mockito .Mockito ;
3242
@@ -39,6 +49,22 @@ public class GitLabSCMSourceTest {
3949 @ ClassRule
4050 public static JenkinsRule j = new JenkinsRule ();
4151
52+ private MockedStatic <GitLabHelper > utilities ;
53+
54+ private MockedConstruction <Sleeper > sleeperMockedConstruction ;
55+
56+ @ Before
57+ public void setUp () {
58+ utilities = Mockito .mockStatic (GitLabHelper .class );
59+ sleeperMockedConstruction = Mockito .mockConstruction (Sleeper .class );
60+ }
61+
62+ @ After
63+ public void tearDown () {
64+ utilities .close ();
65+ sleeperMockedConstruction .close ();
66+ }
67+
4268 @ Test
4369 public void retrieveMRWithEmptyProjectSettings () throws GitLabApiException , IOException , InterruptedException {
4470 GitLabApi gitLabApi = Mockito .mock (GitLabApi .class );
@@ -49,22 +75,103 @@ public void retrieveMRWithEmptyProjectSettings() throws GitLabApiException, IOEx
4975 Mockito .when (gitLabApi .getMergeRequestApi ()).thenReturn (mrApi );
5076 Mockito .when (gitLabApi .getRepositoryApi ()).thenReturn (repoApi );
5177 Mockito .when (projectApi .getProject (any ())).thenReturn (new Project ());
52- try (MockedStatic <GitLabHelper > utilities = Mockito .mockStatic (GitLabHelper .class )) {
53- utilities
54- .when (() -> GitLabHelper .apiBuilder (any (AccessControlled .class ), anyString ()))
55- .thenReturn (gitLabApi );
56- GitLabServers .get ().addServer (new GitLabServer ("" , SERVER , "" ));
57- GitLabSCMSourceBuilder sb =
58- new GitLabSCMSourceBuilder (SOURCE_ID , SERVER , "creds" , "po" , "group/project" , "project" );
59- WorkflowMultiBranchProject project = j .createProject (WorkflowMultiBranchProject .class , PROJECT_NAME );
60- BranchSource source = new BranchSource (sb .build ());
61- source .getSource ()
62- .setTraits (Arrays .asList (new BranchDiscoveryTrait (0 ), new OriginMergeRequestDiscoveryTrait (1 )));
63- project .getSourcesList ().add (source );
64- ByteArrayOutputStream out = new ByteArrayOutputStream ();
65- final TaskListener listener = new StreamTaskListener (out , StandardCharsets .UTF_8 );
66- Set <SCMHead > scmHead = source .getSource ().fetch (listener );
67- assertEquals (0 , scmHead .size ());
68- }
78+ utilities
79+ .when (() -> GitLabHelper .apiBuilder (any (AccessControlled .class ), anyString ()))
80+ .thenReturn (gitLabApi );
81+ GitLabServers .get ().addServer (new GitLabServer ("" , SERVER , "" ));
82+ GitLabSCMSourceBuilder sb =
83+ new GitLabSCMSourceBuilder (SOURCE_ID , SERVER , "creds" , "po" , "group/project" , "project" );
84+ WorkflowMultiBranchProject project = j .createProject (WorkflowMultiBranchProject .class , PROJECT_NAME );
85+ BranchSource source = new BranchSource (sb .build ());
86+ source .getSource ()
87+ .setTraits (Arrays .asList (new BranchDiscoveryTrait (0 ), new OriginMergeRequestDiscoveryTrait (1 )));
88+ project .getSourcesList ().add (source );
89+ ByteArrayOutputStream out = new ByteArrayOutputStream ();
90+ final TaskListener listener = new StreamTaskListener (out , StandardCharsets .UTF_8 );
91+ Set <SCMHead > scmHead = source .getSource ().fetch (listener );
92+ assertEquals (0 , scmHead .size ());
93+ }
94+
95+ @ Test
96+ public void testGetMembersWithNoRetries () throws GitLabApiException {
97+ GitLabApi gitLabApi = Mockito .mock (GitLabApi .class );
98+ ProjectApi projectApi = Mockito .mock (ProjectApi .class );
99+ Mockito .when (gitLabApi .getProjectApi ()).thenReturn (projectApi );
100+ Member mockMember = Mockito .mock (Member .class );
101+ Mockito .when (mockMember .getUsername ()).thenReturn ("example.user" );
102+ Mockito .when (mockMember .getAccessLevel ()).thenReturn (AccessLevel .DEVELOPER );
103+ SCMSourceOwner mockOwner = Mockito .mock (SCMSourceOwner .class );
104+ Mockito .when (projectApi .getAllMembers ("group/project" )).thenReturn (List .of (mockMember ));
105+ utilities
106+ .when (() -> GitLabHelper .apiBuilder (any (AccessControlled .class ), anyString ()))
107+ .thenReturn (gitLabApi );
108+ GitLabServers .get ().addServer (new GitLabServer ("" , SERVER , "" ));
109+ GitLabSCMSourceBuilder sb =
110+ new GitLabSCMSourceBuilder (SOURCE_ID , SERVER , "creds" , "po" , "group/project" , "project" );
111+ GitLabSCMSource source = sb .build ();
112+ source .setOwner (mockOwner );
113+ assertEquals (Map .of ("example.user" , AccessLevel .DEVELOPER ), source .getMembers ());
114+ Sleeper sleeper = sleeperMockedConstruction .constructed ().get (0 );
115+ Mockito .verifyNoInteractions (sleeper );
116+ }
117+
118+ @ Test
119+ public void testGetMembersWithAllRetries () throws GitLabApiException , InterruptedException {
120+ GitLabApi gitLabApi = Mockito .mock (GitLabApi .class );
121+ ProjectApi projectApi = Mockito .mock (ProjectApi .class );
122+ Mockito .when (gitLabApi .getProjectApi ()).thenReturn (projectApi );
123+ SCMSourceOwner mockOwner = Mockito .mock (SCMSourceOwner .class );
124+ GitLabApiException rateLimitException = new GitLabApiException ("Rate limit" , 429 );
125+ Mockito .when (projectApi .getAllMembers ("group/project" )).thenThrow (rateLimitException );
126+ utilities
127+ .when (() -> GitLabHelper .apiBuilder (any (AccessControlled .class ), anyString ()))
128+ .thenReturn (gitLabApi );
129+ GitLabServers .get ().addServer (new GitLabServer ("" , SERVER , "" ));
130+ GitLabSCMSourceBuilder sb =
131+ new GitLabSCMSourceBuilder (SOURCE_ID , SERVER , "creds" , "po" , "group/project" , "project" );
132+ GitLabSCMSource source = sb .build ();
133+ source .setOwner (mockOwner );
134+ assertEquals (Map .of (), source .getMembers ());
135+ Sleeper sleeper = sleeperMockedConstruction .constructed ().get (0 );
136+ Mockito .verify (sleeper , Mockito .times (1 )).sleep (5000 );
137+ Mockito .verify (sleeper , Mockito .times (1 )).sleep (10000 );
138+ Mockito .verify (sleeper , Mockito .times (1 )).sleep (20000 );
139+ Mockito .verify (sleeper , Mockito .times (1 )).sleep (40000 );
140+ Mockito .verify (sleeper , Mockito .times (1 )).sleep (80000 );
141+ Mockito .verify (sleeper , Mockito .times (1 )).sleep (160000 );
142+ Mockito .verifyNoMoreInteractions (sleeper );
143+ }
144+
145+ @ Test
146+ public void testGetMembersWithSomeRetries () throws GitLabApiException , InterruptedException {
147+ GitLabApi gitLabApi = Mockito .mock (GitLabApi .class );
148+ ProjectApi projectApi = Mockito .mock (ProjectApi .class );
149+ Mockito .when (gitLabApi .getProjectApi ()).thenReturn (projectApi );
150+ GitLabApiException rateLimitException = new GitLabApiException ("Rate limit" , 429 );
151+ Member mockMember = Mockito .mock (Member .class );
152+ Mockito .when (mockMember .getUsername ()).thenReturn ("example.user" );
153+ Mockito .when (mockMember .getAccessLevel ()).thenReturn (AccessLevel .DEVELOPER );
154+ SCMSourceOwner mockOwner = Mockito .mock (SCMSourceOwner .class );
155+ AtomicInteger counter = new AtomicInteger ();
156+ Mockito .when (projectApi .getAllMembers ("group/project" )).thenAnswer ((input ) -> {
157+ if (counter .getAndIncrement () < 3 ) {
158+ throw rateLimitException ;
159+ }
160+ return List .of (mockMember );
161+ });
162+ utilities
163+ .when (() -> GitLabHelper .apiBuilder (any (AccessControlled .class ), anyString ()))
164+ .thenReturn (gitLabApi );
165+ GitLabServers .get ().addServer (new GitLabServer ("" , SERVER , "" ));
166+ GitLabSCMSourceBuilder sb =
167+ new GitLabSCMSourceBuilder (SOURCE_ID , SERVER , "creds" , "po" , "group/project" , "project" );
168+ GitLabSCMSource source = sb .build ();
169+ source .setOwner (mockOwner );
170+ assertEquals (Map .of ("example.user" , AccessLevel .DEVELOPER ), source .getMembers ());
171+ Sleeper sleeper = sleeperMockedConstruction .constructed ().get (0 );
172+ Mockito .verify (sleeper , Mockito .times (1 )).sleep (5000 );
173+ Mockito .verify (sleeper , Mockito .times (1 )).sleep (10000 );
174+ Mockito .verify (sleeper , Mockito .times (1 )).sleep (20000 );
175+ Mockito .verifyNoMoreInteractions (sleeper );
69176 }
70177}
0 commit comments