Skip to content

Commit

Permalink
Include userId in BuildData
Browse files Browse the repository at this point in the history
Based on the similar implementation of the datadog plugin [1].
 - the userId is `scm` when the build was triggered by SCM
 - the userId is `timer` when the build was triggered by a timer
 - when the build was triggered by an upstream build, the userId of that
   build is used
 - in all other cases the userId is `anonymous`.

[1] https://github.com/jenkinsci/datadog-plugin/blob/master/src/main/java/org/datadog/jenkins/plugins/datadog/model/BuildData.java#L624
  • Loading branch information
LEDfan committed Nov 22, 2021
1 parent d05825e commit 31b3c7c
Show file tree
Hide file tree
Showing 3 changed files with 139 additions and 4 deletions.
45 changes: 45 additions & 0 deletions src/main/java/jenkins/plugins/logstash/persistence/BuildData.java
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,7 @@
package jenkins.plugins.logstash.persistence;

import hudson.model.Action;
import hudson.model.Cause;
import hudson.model.Environment;
import hudson.model.Executor;
import hudson.model.Result;
Expand All @@ -34,6 +35,8 @@
import hudson.model.Node;
import hudson.tasks.test.AbstractTestResultAction;
import hudson.tasks.test.TestResult;
import hudson.triggers.SCMTrigger;
import hudson.triggers.TimerTrigger;
import jenkins.plugins.logstash.LogstashConfiguration;

import java.util.ArrayList;
Expand Down Expand Up @@ -167,6 +170,7 @@ public List<String> getFailedTests()
private String buildLabel;
private String stageName;
private String agentName;
private String userId;
private int buildNum;
private long buildDuration;
private transient String timestamp; // This belongs in the root object
Expand Down Expand Up @@ -266,6 +270,7 @@ private void initData(Run<?, ?> build, Date currentTime) {
buildNum = build.getNumber();
buildDuration = currentTime.getTime() - build.getStartTimeInMillis();
timestamp = LogstashConfiguration.getInstance().getDateFormatter().format(build.getTimestamp().getTime());
userId = getUserIdFromRun(build);
updateResult();
}

Expand All @@ -283,6 +288,38 @@ public void updateResult()
}
}

private String getUserIdFromRun(Run<?, ?> run) {
for (Cause cause : run.getCauses()) {
String userName = getUserIdFromCause(cause);
if (userName != null) {
return userName;
}
}

if (run.getParent().getClass().getName().equals("hudson.maven.MavenModule")) {
return "maven";
}
return "anonymous";
}

private String getUserIdFromCause(Cause cause){
if (cause instanceof TimerTrigger.TimerTriggerCause) {
return "timer";
} else if (cause instanceof SCMTrigger.SCMTriggerCause) {
return "scm";
} else if (cause instanceof Cause.UserIdCause) {
return ((Cause.UserIdCause) cause).getUserId();
} else if (cause instanceof Cause.UpstreamCause) {
for (Cause upstreamCause : ((Cause.UpstreamCause) cause).getUpstreamCauses()) {
String username = getUserIdFromCause(upstreamCause);
if (username != null) {
return username;
}
}
}
return null;
}

@Override
public String toString() {
Gson gson = new GsonBuilder().create();
Expand Down Expand Up @@ -469,4 +506,12 @@ public String getAgentName() {
public void setAgentName(String agentName) {
this.agentName = agentName;
}

public String getUserId() {
return userId;
}

public void setUserId(String userId) {
this.userId = userId;
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -124,6 +124,7 @@ public void before() throws Exception {
when(mockBuild.getCharset()).thenReturn(Charset.defaultCharset());
when(mockExecutor.getOwner()).thenReturn(mockComputer);
when(mockComputer.getNode()).thenReturn(null);
when(mockBuild.getCauses()).thenReturn(Collections.emptyList());

when(mockTestResultAction.getTotalCount()).thenReturn(0);
when(mockTestResultAction.getSkipCount()).thenReturn(0);
Expand Down Expand Up @@ -160,7 +161,7 @@ public void constructorSuccess() throws Exception {
// This also lets us verify that in the instantiation failure cases we do not construct BuildData.
verify(mockBuild).getId();
verify(mockBuild, times(2)).getResult();
verify(mockBuild, times(2)).getParent();
verify(mockBuild, times(3)).getParent();
verify(mockBuild, times(2)).getProject();
verify(mockBuild, times(1)).getStartTimeInMillis();
verify(mockBuild, times(2)).getDisplayName();
Expand All @@ -177,6 +178,7 @@ public void constructorSuccess() throws Exception {
verify(mockBuild).getEnvironments();
verify(mockBuild).getEnvironment(null);
verify(mockBuild).getCharset();
verify(mockBuild).getCauses();

verify(mockTestResultAction).getTotalCount();
verify(mockTestResultAction).getSkipCount();
Expand Down
Original file line number Diff line number Diff line change
@@ -1,10 +1,14 @@
package jenkins.plugins.logstash.persistence;

import static org.mockito.ArgumentMatchers.any;
import static org.mockito.Mockito.atLeast;
import static org.mockito.Mockito.atLeastOnce;
import static org.mockito.Mockito.atMostOnce;
import static org.mockito.Mockito.doAnswer;
import static org.mockito.Mockito.times;
import static org.mockito.Mockito.verify;
import static org.mockito.Mockito.verifyNoMoreInteractions;
import static org.powermock.api.mockito.PowerMockito.mock;
import static org.powermock.api.mockito.PowerMockito.when;

import java.util.Arrays;
Expand All @@ -13,8 +17,12 @@
import java.util.GregorianCalendar;
import java.util.HashMap;
import java.util.HashSet;
import java.util.List;
import java.util.Map;

import hudson.model.Cause;
import hudson.triggers.SCMTrigger;
import hudson.triggers.TimerTrigger;
import org.junit.After;
import org.junit.Assert;
import org.junit.Before;
Expand Down Expand Up @@ -59,7 +67,7 @@ public class BuildDataTest {
+ "\"rootProjectName\":\"RootBuildDataTest\",\"rootFullProjectName\":\"parent/RootBuildDataTest\","
+ "\"rootProjectDisplayName\":\"Root BuildData Test\",\"rootBuildNum\":456,\"buildVariables\":{},"
+ "\"sensitiveBuildVariables\":[],\"testResults\":{\"totalCount\":0,\"skipCount\":0,\"failCount\":0, \"passCount\":0,"
+ "\"failedTests\":[], \"failedTestsWithErrorDetail\":[]}}";
+ "\"failedTests\":[], \"failedTestsWithErrorDetail\":[]}, \"userId\":\"anonymous\"}";

@Mock AbstractBuild mockBuild;
@Mock AbstractBuild mockRootBuild;
Expand Down Expand Up @@ -130,11 +138,12 @@ public void after() throws Exception {
private void verifyMocks() throws Exception
{
verify(mockProject).getName();
verify(mockProject).getFullName();
verify(mockProject, atLeastOnce()).getFullName();
verify(mockProject, atMostOnce()).getUrl();

verify(mockBuild).getId();
verify(mockBuild, times(2)).getResult();
verify(mockBuild, times(2)).getParent();
verify(mockBuild, atLeast(2)).getParent();
verify(mockBuild).getDisplayName();
verify(mockBuild).getFullDisplayName();
verify(mockBuild).getDescription();
Expand All @@ -149,6 +158,7 @@ private void verifyMocks() throws Exception
verify(mockBuild).getSensitiveBuildVariables();
verify(mockBuild).getEnvironments();
verify(mockBuild).getEnvironment(mockListener);
verify(mockBuild).getCauses();

verify(mockExecutor).getOwner();

Expand Down Expand Up @@ -404,4 +414,82 @@ public void rootProjectFullName() throws Exception
verifyMocks();
verifyTestResultActions();
}

@Test
public void userIdCauseToUserId() throws Exception {
when(mockBuild.getId()).thenReturn("TEST_JOB_123");
when(mockBuild.getUrl()).thenReturn("http://localhost:8080/jenkins/jobs/PROJECT_NAME/123");
when(mockBuild.getCauses()).thenReturn(Collections.singletonList(new Cause.UserIdCause("myUserId")));

BuildData buildData = new BuildData(mockBuild, mockDate, mockListener);

Assert.assertEquals(buildData.getUserId(), "myUserId");

verifyMocks();
verifyTestResultActions();
}

@Test
public void timerCauseToUserId() throws Exception {
when(mockBuild.getId()).thenReturn("TEST_JOB_123");
when(mockBuild.getUrl()).thenReturn("http://localhost:8080/jenkins/jobs/PROJECT_NAME/123");
when(mockBuild.getCauses()).thenReturn(Collections.singletonList(new TimerTrigger.TimerTriggerCause()));

BuildData buildData = new BuildData(mockBuild, mockDate, mockListener);

Assert.assertEquals(buildData.getUserId(), "timer");

verifyMocks();
verifyTestResultActions();
}

@Test
public void scmCauseToUserId() throws Exception {
when(mockBuild.getId()).thenReturn("TEST_JOB_123");
when(mockBuild.getUrl()).thenReturn("http://localhost:8080/jenkins/jobs/PROJECT_NAME/123");
when(mockBuild.getCauses()).thenReturn(Collections.singletonList(new SCMTrigger.SCMTriggerCause()));

BuildData buildData = new BuildData(mockBuild, mockDate, mockListener);

Assert.assertEquals(buildData.getUserId(), "scm");

verifyMocks();
verifyTestResultActions();
}

@Test
public void upstreamCauseToUserId() throws Exception {
AbstractBuild upstreamProject = mock(AbstractBuild.class);

when(upstreamProject.getCauses()).thenReturn(Collections.singletonList(new Cause.UserIdCause("myUpstreamUserId")));
when(upstreamProject.getParent()).thenReturn(mockProject);
when(upstreamProject.getNumber()).thenReturn(10);


when(mockBuild.getId()).thenReturn("TEST_JOB_123");
when(mockBuild.getUrl()).thenReturn("http://localhost:8080/jenkins/jobs/PROJECT_NAME/123");
List<Cause> causes = Collections.singletonList(new Cause.UpstreamCause(upstreamProject));
when(mockBuild.getCauses()).thenReturn(causes);

BuildData buildData = new BuildData(mockBuild, mockDate, mockListener);

Assert.assertEquals(buildData.getUserId(), "myUpstreamUserId");

verifyMocks();
verifyTestResultActions();
}

@Test
public void fallBackUserId() throws Exception {
when(mockBuild.getId()).thenReturn("TEST_JOB_123");
when(mockBuild.getUrl()).thenReturn("http://localhost:8080/jenkins/jobs/PROJECT_NAME/123");
when(mockBuild.getCauses()).thenReturn(Collections.emptyList());

BuildData buildData = new BuildData(mockBuild, mockDate, mockListener);

Assert.assertEquals(buildData.getUserId(), "anonymous");

verifyMocks();
verifyTestResultActions();
}
}

0 comments on commit 31b3c7c

Please sign in to comment.