| // Copyright (C) 2021 The Android Open Source Project |
| // |
| // Licensed under the Apache License, Version 2.0 (the "License"); |
| // you may not use this file except in compliance with the License. |
| // You may obtain a copy of the License at |
| // |
| // http://www.apache.org/licenses/LICENSE-2.0 |
| // |
| // Unless required by applicable law or agreed to in writing, software |
| // distributed under the License is distributed on an "AS IS" BASIS, |
| // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
| // See the License for the specific language governing permissions and |
| // limitations under the License. |
| |
| package com.googlesource.gerrit.plugins.eventseiffel.mapping; |
| |
| import static org.junit.Assert.assertEquals; |
| import static org.junit.Assert.assertNotNull; |
| |
| import com.google.common.base.Charsets; |
| import com.google.common.collect.Lists; |
| import com.google.gerrit.acceptance.PushOneCommit; |
| import com.google.gerrit.acceptance.TestPlugin; |
| import com.google.gerrit.extensions.api.changes.NotifyHandling; |
| import com.google.gerrit.extensions.api.changes.ReviewInput; |
| import com.google.gerrit.extensions.api.changes.RevisionApi; |
| import com.google.gerrit.extensions.common.AccountInfo; |
| import com.google.gerrit.extensions.common.ChangeInfo; |
| import com.google.gerrit.extensions.common.CommitInfo; |
| import com.google.gerrit.extensions.common.GitPerson; |
| import com.google.gerrit.extensions.common.RevisionInfo; |
| import com.google.gerrit.extensions.events.RevisionCreatedListener; |
| import com.google.gerrit.extensions.restapi.NotImplementedException; |
| import com.google.gerrit.extensions.restapi.RestApiException; |
| import com.google.inject.AbstractModule; |
| import com.google.inject.Singleton; |
| import com.googlesource.gerrit.plugins.eventseiffel.EiffelEventsTest; |
| import com.googlesource.gerrit.plugins.eventseiffel.config.EventMappingConfig; |
| import com.googlesource.gerrit.plugins.eventseiffel.eiffel.dto.EiffelArtifactCreatedEventInfo; |
| import com.googlesource.gerrit.plugins.eventseiffel.eiffel.dto.EiffelChangeInfo; |
| import com.googlesource.gerrit.plugins.eventseiffel.eiffel.dto.EiffelCompositionDefinedEventInfo; |
| import com.googlesource.gerrit.plugins.eventseiffel.eiffel.dto.EiffelEventType; |
| import com.googlesource.gerrit.plugins.eventseiffel.eiffel.dto.EiffelGitIdentifierInfo; |
| import com.googlesource.gerrit.plugins.eventseiffel.eiffel.dto.EiffelLinkInfo; |
| import com.googlesource.gerrit.plugins.eventseiffel.eiffel.dto.EiffelLinkType; |
| import com.googlesource.gerrit.plugins.eventseiffel.eiffel.dto.EiffelMetaInfo; |
| import com.googlesource.gerrit.plugins.eventseiffel.eiffel.dto.EiffelPersonInfo; |
| import com.googlesource.gerrit.plugins.eventseiffel.eiffel.dto.EiffelSourceChangeCreatedEventInfo; |
| import com.googlesource.gerrit.plugins.eventseiffel.eiffel.dto.EiffelSourceChangeSubmittedEventInfo; |
| import com.googlesource.gerrit.plugins.eventseiffel.parsing.PatchsetCreationData; |
| import java.net.URLEncoder; |
| import java.time.Instant; |
| import java.util.List; |
| import java.util.UUID; |
| import org.eclipse.jgit.lib.PersonIdent; |
| import org.eclipse.jgit.revwalk.RevCommit; |
| import org.junit.Before; |
| import org.junit.Test; |
| |
| @TestPlugin( |
| name = "events-eiffel", |
| sysModule = "com.googlesource.gerrit.plugins.eventseiffel.mapping.EventMappingIT$TestModule") |
| public class EventMappingIT extends EiffelEventsTest { |
| private static final String COMMIT_SHA1 = "58117b5a121eb516c2cdca463c51250ad3de9cd3"; |
| private static final String REPO_NAME = "repo/name"; |
| private static final String BRANCH = "main"; |
| private static final int CHANGE_NUMBER = 1234; |
| private static final String AUTHOR_EMAIL = "jane.doe@company.com"; |
| private static final String AUTHOR_NAME = "Jane Doe"; |
| private static final Long EPOCH_MILLIS = 978307261000l; |
| private static final List<UUID> PARENT_UUIDS = Lists.newArrayList(UUID.randomUUID()); |
| private static final UUID SCC_UUID = UUID.randomUUID(); |
| private static final UUID CD_UUID = UUID.randomUUID(); |
| private static final UUID SCS_UUID = UUID.randomUUID(); |
| |
| EiffelEventMapper mapper; |
| |
| @Before |
| public void setUp() { |
| mapper = plugin.getSysInjector().getInstance(EiffelEventMapper.class); |
| } |
| |
| @Test |
| public void sccFromPatchsetCreationData() throws Exception { |
| EiffelSourceChangeCreatedEventInfo event = |
| mapper.toScc(new PatchsetCreationData(new TestEvent()), PARENT_UUIDS); |
| assertPersonInfo(event.data.author, AUTHOR_NAME, AUTHOR_EMAIL, null); |
| assertGitIdentifier(event.data.gitIdentifier, REPO_NAME, BRANCH, COMMIT_SHA1); |
| assertChangeInfo(event.data.change, String.valueOf(CHANGE_NUMBER), REPO_NAME, COMMIT_SHA1); |
| assertSccMeta(event.meta, EPOCH_MILLIS); |
| assertSccLinks(event.links); |
| } |
| |
| @Test |
| public void sccFromRevCommitWhereAuthorDoesNotHaveAccount() throws Exception { |
| RevCommit accountlessAuthor = |
| commitBuilder().author(new PersonIdent(AUTHOR_NAME, AUTHOR_EMAIL)).create(); |
| |
| EiffelSourceChangeCreatedEventInfo event = |
| mapper.toScc(accountlessAuthor, project.get(), "master", PARENT_UUIDS); |
| |
| assertPersonInfo(event.data.author, AUTHOR_NAME, AUTHOR_EMAIL, null); |
| assertGitIdentifier( |
| event.data.gitIdentifier, project.get(), "master", accountlessAuthor.getName()); |
| assertChangeInfo(event.data.change, null, project.get(), accountlessAuthor.getName()); |
| assertSccMeta(event.meta, commitTimeInEpochMillis(accountlessAuthor)); |
| assertSccLinks(event.links); |
| } |
| |
| @Test |
| public void sccFromRevCommitWhereCommitterHasAccount() throws Exception { |
| RevCommit authorWithAccount = |
| commitBuilder().author(new PersonIdent(admin.fullName(), admin.email())).create(); |
| |
| EiffelSourceChangeCreatedEventInfo event = |
| mapper.toScc(authorWithAccount, project.get(), "master", PARENT_UUIDS); |
| |
| assertPersonInfo(event.data.author, admin.fullName(), admin.email(), admin.username()); |
| assertGitIdentifier( |
| event.data.gitIdentifier, project.get(), "master", authorWithAccount.getName()); |
| assertChangeInfo(event.data.change, null, project.get(), authorWithAccount.getName()); |
| assertSccMeta(event.meta, commitTimeInEpochMillis(authorWithAccount)); |
| assertSccLinks(event.links); |
| } |
| |
| @Test |
| public void sccFromChangeRevCommit() throws Exception { |
| PushOneCommit.Result res = createChange(); |
| sccFromChangeRevCommit(res); |
| } |
| |
| @Test |
| public void sccFromChangeRevCommitThatIsNotCurrent() throws Exception { |
| PushOneCommit.Result res = createChange(); |
| amendChange(res.getChangeId()); |
| sccFromChangeRevCommit(res); |
| } |
| |
| private void sccFromChangeRevCommit(PushOneCommit.Result result) throws Exception { |
| EiffelSourceChangeCreatedEventInfo event = |
| mapper.toScc(result.getCommit(), project.get(), "master", PARENT_UUIDS); |
| |
| assertPersonInfo(event.data.author, admin.fullName(), admin.email(), admin.username()); |
| assertGitIdentifier( |
| event.data.gitIdentifier, project.get(), "master", result.getCommit().getName()); |
| assertChangeInfo( |
| event.data.change, |
| String.valueOf(result.getPatchSetId().changeId().get()), |
| project.get(), |
| result.getCommit().getName()); |
| assertSccMeta( |
| event.meta, Long.valueOf(result.getChange().currentPatchSet().createdOn().toEpochMilli())); |
| assertSccLinks(event.links); |
| } |
| |
| @Test |
| public void scsFromRevCommitWithoutSubmitter() throws Exception { |
| /* The initial commit is created by the server that doesn't have an account */ |
| RevCommit revCommit = |
| commitBuilder().committer(new PersonIdent(AUTHOR_NAME, AUTHOR_EMAIL)).create(); |
| EiffelSourceChangeSubmittedEventInfo event = |
| mapper.toScs(revCommit, project.get(), "master", null, null, PARENT_UUIDS, SCC_UUID); |
| |
| assertPersonInfo(event.data.submitter, AUTHOR_NAME, AUTHOR_EMAIL, null); |
| assertGitIdentifier(event.data.gitIdentifier, project.get(), "master", revCommit.getName()); |
| assertScsMeta(event.meta, commitTimeInEpochMillis(revCommit)); |
| assertScsLinks(event.links); |
| } |
| |
| @Test |
| public void scsFromChangeRevCommitWithoutSubmitter() throws Exception { |
| /* The initial commit is created by the server that doesn't have an account */ |
| PushOneCommit.Result res = createChange(); |
| ChangeInfo change = approveAndMerge(res); |
| |
| EiffelSourceChangeSubmittedEventInfo event = |
| mapper.toScs(res.getCommit(), project.get(), "master", null, null, PARENT_UUIDS, SCC_UUID); |
| |
| assertPersonInfo(event.data.submitter, admin.fullName(), admin.email(), admin.username()); |
| assertGitIdentifier( |
| event.data.gitIdentifier, project.get(), "master", res.getCommit().getName()); |
| assertScsMeta(event.meta, Long.valueOf(change.submitted.getTime())); |
| } |
| |
| @Test |
| public void scsFromRevCommitWithSubmitterAndSubmittedAt() throws Exception { |
| /* The initial commit is created by the server that doesn't have an account */ |
| RevCommit revCommit = |
| commitBuilder().committer(new PersonIdent(AUTHOR_NAME, AUTHOR_EMAIL)).create(); |
| AccountInfo submitter = gApi.accounts().id(user.username()).get(); |
| Long submittedAt = Instant.now().toEpochMilli(); |
| EiffelSourceChangeSubmittedEventInfo event = |
| mapper.toScs( |
| revCommit, project.get(), "master", submitter, submittedAt, PARENT_UUIDS, SCC_UUID); |
| |
| assertPersonInfo(event.data.submitter, submitter.name, submitter.email, submitter.username); |
| assertGitIdentifier(event.data.gitIdentifier, project.get(), "master", revCommit.getName()); |
| assertScsMeta(event.meta, submittedAt); |
| assertScsLinks(event.links); |
| } |
| |
| @Test |
| public void scsFromRevCommitWithSubmitterButNotSubmittedAt() throws Exception { |
| /* The initial commit is created by the server that doesn't have an account */ |
| RevCommit revCommit = |
| commitBuilder().committer(new PersonIdent(AUTHOR_NAME, AUTHOR_EMAIL)).create(); |
| AccountInfo submitter = gApi.accounts().id(user.username()).get(); |
| EiffelSourceChangeSubmittedEventInfo event = |
| mapper.toScs(revCommit, project.get(), "master", submitter, null, PARENT_UUIDS, SCC_UUID); |
| |
| assertPersonInfo(event.data.submitter, submitter.name, submitter.email, submitter.username); |
| assertGitIdentifier(event.data.gitIdentifier, project.get(), "master", revCommit.getName()); |
| assertScsMeta(event.meta, commitTimeInEpochMillis(revCommit)); |
| assertScsLinks(event.links); |
| } |
| |
| @Test |
| public void artcTest() throws Exception { |
| EiffelArtifactCreatedEventInfo event = |
| mapper.toArtc(REPO_NAME, TAG_NAME, EPOCH_MILLIS, CD_UUID); |
| |
| assertEquals(tagPURL(REPO_NAME, TAG_NAME), event.data.identity); |
| assertArtcMeta(event.meta, EPOCH_MILLIS); |
| assertArtcLink(event.links); |
| } |
| |
| @Test |
| public void cdTest() throws Exception { |
| EiffelCompositionDefinedEventInfo event = |
| mapper.toCd(REPO_NAME, TAG_NAME, EPOCH_MILLIS, SCS_UUID); |
| |
| assertEquals(tagCompositionName(REPO_NAME), event.data.name); |
| assertEquals(TAG_NAME, event.data.version); |
| assertCdMeta(event.meta, EPOCH_MILLIS); |
| assertCdLink(event.links); |
| } |
| |
| private void assertSccMeta(EiffelMetaInfo meta, Long time) { |
| assertMeta(meta, EiffelEventType.SCC, EiffelSourceChangeCreatedEventInfo.EVENT_VERSION, time); |
| } |
| |
| private void assertScsMeta(EiffelMetaInfo meta, Long time) { |
| assertMeta(meta, EiffelEventType.SCS, EiffelSourceChangeSubmittedEventInfo.EVENT_VERSION, time); |
| } |
| |
| private void assertArtcMeta(EiffelMetaInfo meta, Long time) { |
| assertMeta( |
| meta, EiffelEventType.ARTC, EiffelSourceChangeSubmittedEventInfo.EVENT_VERSION, time); |
| } |
| |
| private void assertCdMeta(EiffelMetaInfo meta, Long time) { |
| assertMeta(meta, EiffelEventType.CD, EiffelSourceChangeSubmittedEventInfo.EVENT_VERSION, time); |
| } |
| |
| private void assertMeta(EiffelMetaInfo meta, EiffelEventType type, String version, Long time) { |
| assertEquals(type, meta.type); |
| assertEquals(version, meta.version); |
| assertEquals(time, meta.time); |
| assertNotNull(meta.id); |
| assertEquals("Gerrit", meta.source.domainId); |
| assertEquals(HOST_NAME, meta.source.host); |
| assertEquals(PLUGIN_NAME, meta.source.name); |
| assertEquals( |
| String.format("pkg:maven/com.googlesource.gerrit.plugins/%s@%s", PLUGIN_NAME, VERSION), |
| meta.source.serializer); |
| } |
| |
| private void assertChangeInfo( |
| EiffelChangeInfo change, String changeNumber, String repoName, String sha1) { |
| assertEquals(changeNumber, change.id); |
| assertEquals("Gerrit", change.tracker); |
| assertEquals( |
| String.format( |
| "%s/a/projects/%s/commits/%s", |
| WEB_URL, URLEncoder.encode(repoName, Charsets.UTF_8), sha1), |
| change.details); |
| } |
| |
| private void assertGitIdentifier( |
| EiffelGitIdentifierInfo git, String repoName, String branch, String sha1) { |
| assertEquals(repoName, git.repoName); |
| assertEquals(branch, git.branch); |
| assertEquals(sha1, git.commitId); |
| assertEquals(String.format("ssh://%s:%d/%s", HOST_NAME, SSH_PORT, repoName), git.repoUri); |
| } |
| |
| private void assertPersonInfo( |
| EiffelPersonInfo person, String name, String email, String username) { |
| assertEquals(name, person.name); |
| assertEquals(email, person.email); |
| assertEquals(username, person.id); |
| } |
| |
| private ChangeInfo approveAndMerge(PushOneCommit.Result res) throws RestApiException { |
| RevisionApi revision = gApi.changes().id(res.getChangeId()).current(); |
| revision.review(ReviewInput.approve()); |
| revision.submit(); |
| return gApi.changes().id(res.getChangeId()).get(); |
| } |
| |
| private void assertSccLinks(EiffelLinkInfo... links) throws Exception { |
| assertSccLinks(PARENT_UUIDS, links); |
| } |
| |
| private void assertScsLinks(EiffelLinkInfo... links) throws Exception { |
| assertScsLinks(PARENT_UUIDS, SCC_UUID, links); |
| } |
| |
| private void assertArtcLink(EiffelLinkInfo... links) throws Exception { |
| assertEquals(1, links.length); |
| assertEquals(EiffelLinkType.COMPOSITION, links[0].type); |
| assertEquals(CD_UUID, links[0].target); |
| } |
| |
| private void assertCdLink(EiffelLinkInfo... links) throws Exception { |
| assertEquals(1, links.length); |
| assertEquals(EiffelLinkType.ELEMENT, links[0].type); |
| assertEquals(SCS_UUID, links[0].target); |
| } |
| |
| static class TestEvent implements RevisionCreatedListener.Event { |
| @Override |
| public RevisionInfo getRevision() { |
| CommitInfo cInfo = new CommitInfo(); |
| cInfo.commit = COMMIT_SHA1; |
| GitPerson author = new GitPerson(); |
| author.email = AUTHOR_EMAIL; |
| author.name = AUTHOR_NAME; |
| cInfo.author = author; |
| cInfo.parents = List.of(); |
| RevisionInfo rInfo = new RevisionInfo(); |
| rInfo.commit = cInfo; |
| return rInfo; |
| } |
| |
| @Override |
| public ChangeInfo getChange() { |
| ChangeInfo cInfo = new ChangeInfo(); |
| cInfo.project = REPO_NAME; |
| cInfo.branch = BRANCH; |
| cInfo._number = CHANGE_NUMBER; |
| return cInfo; |
| } |
| |
| @Override |
| public AccountInfo getWho() { |
| throw new NotImplementedException(); |
| } |
| |
| @Override |
| public Instant getWhen() { |
| return Instant.ofEpochMilli(EPOCH_MILLIS); |
| } |
| |
| @Override |
| public NotifyHandling getNotify() { |
| throw new NotImplementedException(); |
| } |
| } |
| |
| public static class TestModule extends AbstractModule { |
| @Override |
| protected void configure() { |
| bind(EventMappingConfig.class).toProvider(EventMappingConfig.Provider.class); |
| bind(EiffelEventFactory.class) |
| .toProvider(EiffelEventsTest.TestEventFactoryProvider.class) |
| .in(Singleton.class); |
| bind(EiffelEventMapper.class); |
| } |
| } |
| } |