blob: b2d6d7842bc4fe430415759e84397b7c558b2387 [file] [log] [blame]
/*
* Licensed to the Apache Software Foundation (ASF) under one
* or more contributor license agreements. See the NOTICE file
* distributed with this work for additional information
* regarding copyright ownership. The ASF licenses this file
* to you 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 org.apache.maven.artifact.repository.metadata;
import javax.xml.stream.XMLInputFactory;
import javax.xml.stream.XMLOutputFactory;
import java.io.ByteArrayInputStream;
import java.io.ByteArrayOutputStream;
import java.text.DateFormat;
import java.text.SimpleDateFormat;
import java.util.Date;
import java.util.GregorianCalendar;
import java.util.TimeZone;
import com.ctc.wstx.stax.WstxInputFactory;
import com.ctc.wstx.stax.WstxOutputFactory;
import org.apache.maven.artifact.repository.metadata.io.MetadataStaxReader;
import org.apache.maven.artifact.repository.metadata.io.MetadataStaxWriter;
import org.eclipse.aether.artifact.Artifact;
import org.eclipse.aether.artifact.DefaultArtifact;
import org.junit.jupiter.api.BeforeEach;
import org.junit.jupiter.api.Test;
import static org.junit.jupiter.api.Assertions.assertEquals;
import static org.junit.jupiter.api.Assertions.assertFalse;
import static org.junit.jupiter.api.Assertions.assertNotNull;
import static org.junit.jupiter.api.Assertions.assertTrue;
class MetadataTest {
Artifact artifact;
Metadata target;
@BeforeEach
void before() {
artifact = new DefaultArtifact("myGroup:myArtifact:1.0-SNAPSHOT");
target = createMetadataFromArtifact(artifact);
}
/*--- START test common metadata ---*/
@Test
void mergeEmptyMetadata() throws Exception {
Metadata metadata = new Metadata();
assertFalse(metadata.merge(new Metadata()));
}
@Test
void mergeDifferentGAV() throws Exception {
// merge implicitly assumes that merge is only called on the same GAV and does not perform any validation here!
Metadata source = new Metadata();
source.setArtifactId("source-artifact");
source.setGroupId("source-group");
source.setVersion("2.0");
assertFalse(target.merge(source));
assertEquals("myArtifact", target.getArtifactId());
assertEquals("myGroup", target.getGroupId());
assertEquals("1.0-SNAPSHOT", target.getVersion());
}
/*--- END test common metadata ---*/
/*--- START test "groupId/artifactId/version" metadata ---*/
@Test
void mergeSnapshotWithEmptyList() throws Exception {
Snapshot snapshot = new Snapshot();
snapshot.setBuildNumber(3);
snapshot.setTimestamp("20200710.072412");
target.getVersioning().setSnapshot(snapshot);
target.getVersioning().setLastUpdated("20200921071745");
SnapshotVersion sv = new SnapshotVersion();
sv.setClassifier("sources");
sv.setExtension("jar");
sv.setUpdated("20200710072412");
target.getVersioning().addSnapshotVersion(sv);
Metadata source = createMetadataFromArtifact(artifact);
// nothing should be actually changed, but still merge returns true
assertTrue(target.merge(source));
// NOTE! Merge updates last updated to source
assertEquals("20200921071745", source.getVersioning().getLastUpdated());
assertEquals("myArtifact", target.getArtifactId());
assertEquals("myGroup", target.getGroupId());
assertEquals(3, target.getVersioning().getSnapshot().getBuildNumber());
assertEquals("20200710.072412", target.getVersioning().getSnapshot().getTimestamp());
assertEquals(1, target.getVersioning().getSnapshotVersions().size());
assertEquals(
"sources", target.getVersioning().getSnapshotVersions().get(0).getClassifier());
assertEquals("jar", target.getVersioning().getSnapshotVersions().get(0).getExtension());
assertEquals(
"20200710072412",
target.getVersioning().getSnapshotVersions().get(0).getUpdated());
}
@Test
void mergeWithSameSnapshotWithDifferentVersionsAndNewerLastUpdated() {
Metadata source = createMetadataFromArtifact(artifact);
Date before = new Date(System.currentTimeMillis() - 5000);
Date after = new Date(System.currentTimeMillis());
addSnapshotVersion(target.getVersioning(), "jar", before, "1", 1);
SnapshotVersion sv2 =
addSnapshotVersion(source.getVersioning(), "jar", after, "1.0-" + formatDate(after, true) + "-2", 2);
SnapshotVersion sv3 =
addSnapshotVersion(source.getVersioning(), "pom", after, "1.0-" + formatDate(after, true) + "-2", 2);
assertTrue(target.merge(source));
Versioning actualVersioning = target.getVersioning();
assertEquals(2, actualVersioning.getSnapshotVersions().size());
assertEquals(sv2, actualVersioning.getSnapshotVersions().get(0));
assertEquals(sv3, actualVersioning.getSnapshotVersions().get(1));
assertEquals(formatDate(after, false), actualVersioning.getLastUpdated());
assertEquals(formatDate(after, true), actualVersioning.getSnapshot().getTimestamp());
assertEquals(2, actualVersioning.getSnapshot().getBuildNumber());
}
@Test
void mergeWithSameSnapshotWithDifferentVersionsAndOlderLastUpdated() {
Metadata source = createMetadataFromArtifact(artifact);
Date before = new Date(System.currentTimeMillis() - 5000);
Date after = new Date(System.currentTimeMillis());
SnapshotVersion sv1 = addSnapshotVersion(target.getVersioning(), after, artifact);
addSnapshotVersion(source.getVersioning(), before, artifact);
// nothing should be updated, as the target was already updated at a later date than source
assertFalse(target.merge(source));
assertEquals(1, target.getVersioning().getSnapshotVersions().size());
assertEquals(sv1, target.getVersioning().getSnapshotVersions().get(0));
assertEquals(formatDate(after, false), target.getVersioning().getLastUpdated());
assertEquals(
formatDate(after, true), target.getVersioning().getSnapshot().getTimestamp());
}
@Test
void mergeWithSameSnapshotWithSameVersionAndTimestamp() {
Metadata source = createMetadataFromArtifact(artifact);
Date date = new Date();
addSnapshotVersion(target.getVersioning(), date, artifact);
SnapshotVersion sv1 = addSnapshotVersion(source.getVersioning(), date, artifact);
// although nothing has changed merge returns true, as the last modified date is equal
// TODO: improve merge here?
assertTrue(target.merge(source));
assertEquals(1, target.getVersioning().getSnapshotVersions().size());
assertEquals(sv1, target.getVersioning().getSnapshotVersions().get(0));
assertEquals(formatDate(date, false), target.getVersioning().getLastUpdated());
assertEquals(
formatDate(date, true), target.getVersioning().getSnapshot().getTimestamp());
}
@Test
void mergeLegacyWithSnapshotLegacy() {
Metadata source = createMetadataFromArtifact(artifact);
Date before = new Date(System.currentTimeMillis() - 5000);
Date after = new Date(System.currentTimeMillis());
// legacy metadata did not have "versioning.snapshotVersions"
addSnapshotVersionLegacy(target.getVersioning(), before, 1);
addSnapshotVersionLegacy(source.getVersioning(), after, 2);
// although nothing has changed merge returns true, as the last modified date is equal
// TODO: improve merge here?
assertTrue(target.merge(source));
assertEquals(0, target.getVersioning().getSnapshotVersions().size());
assertEquals(formatDate(after, false), target.getVersioning().getLastUpdated());
assertEquals(
formatDate(after, true), target.getVersioning().getSnapshot().getTimestamp());
}
@Test
void mergeLegacyWithSnapshot() {
Metadata source = createMetadataFromArtifact(artifact);
Date before = new Date(System.currentTimeMillis() - 5000);
Date after = new Date(System.currentTimeMillis());
// legacy metadata did not have "versioning.snapshotVersions"
addSnapshotVersionLegacy(target.getVersioning(), before, 1);
addSnapshotVersion(source.getVersioning(), after, artifact);
// although nothing has changed merge returns true, as the last modified date is equal
// TODO: improve merge here?
assertTrue(target.merge(source));
// never convert from legacy format to v1.1 format
assertEquals(0, target.getVersioning().getSnapshotVersions().size());
assertEquals(formatDate(after, false), target.getVersioning().getLastUpdated());
assertEquals(
formatDate(after, true), target.getVersioning().getSnapshot().getTimestamp());
}
@Test
void mergeWithSnapshotLegacy() {
Metadata source = createMetadataFromArtifact(artifact);
Date before = new Date(System.currentTimeMillis() - 5000);
Date after = new Date(System.currentTimeMillis());
addSnapshotVersion(target.getVersioning(), before, artifact);
// legacy metadata did not have "versioning.snapshotVersions"
addSnapshotVersionLegacy(source.getVersioning(), after, 2);
// although nothing has changed merge returns true, as the last modified date is equal
// TODO: improve merge here?
assertTrue(target.merge(source));
// the result must be legacy format as well
assertEquals(0, target.getVersioning().getSnapshotVersions().size());
assertEquals(formatDate(after, false), target.getVersioning().getLastUpdated());
assertEquals(
formatDate(after, true), target.getVersioning().getSnapshot().getTimestamp());
assertEquals(2, target.getVersioning().getSnapshot().getBuildNumber());
}
/*-- END test "groupId/artifactId/version" metadata ---*/
@Test
void testRoundtrip() throws Exception {
System.setProperty(XMLInputFactory.class.getName(), WstxInputFactory.class.getName());
System.setProperty(XMLOutputFactory.class.getName(), WstxOutputFactory.class.getName());
Metadata source = new Metadata(org.apache.maven.artifact.repository.metadata.v4.Metadata.newBuilder(
createMetadataFromArtifact(artifact).getDelegate(), true)
.modelEncoding("UTF-16")
.build());
ByteArrayOutputStream baos = new ByteArrayOutputStream();
new MetadataStaxWriter().write(baos, source.getDelegate());
Metadata source2 =
new Metadata(new MetadataStaxReader().read(new ByteArrayInputStream(baos.toByteArray()), true));
assertNotNull(source2);
}
/*-- START helper methods to populate metadata objects ---*/
private static final String SNAPSHOT = "SNAPSHOT";
private static final String DEFAULT_SNAPSHOT_TIMESTAMP_FORMAT = "yyyyMMdd.HHmmss";
private static final String DEFAULT_DATE_FORMAT = "yyyyMMddHHmmss";
private static String formatDate(Date date, boolean forSnapshotTimestamp) {
// logic from metadata.mdo, class "Versioning"
TimeZone timezone = TimeZone.getTimeZone("UTC");
DateFormat fmt =
new SimpleDateFormat(forSnapshotTimestamp ? DEFAULT_SNAPSHOT_TIMESTAMP_FORMAT : DEFAULT_DATE_FORMAT);
fmt.setCalendar(new GregorianCalendar());
fmt.setTimeZone(timezone);
return fmt.format(date);
}
private static Metadata createMetadataFromArtifact(Artifact artifact) {
Metadata metadata = new Metadata();
metadata.setArtifactId(artifact.getArtifactId());
metadata.setGroupId(artifact.getGroupId());
metadata.setVersion(artifact.getVersion());
metadata.setVersioning(new Versioning());
return metadata;
}
private static SnapshotVersion addSnapshotVersion(Versioning versioning, Date timestamp, Artifact artifact) {
int buildNumber = 1;
// this generates timestamped versions like maven-resolver-provider:
// https://github.com/apache/maven/blob/03df5f7c639db744a3597c7175c92c8e2a27767b/maven-resolver-provider/src/main/java/org/apache/maven/repository/internal/RemoteSnapshotMetadata.java#L79
String version = artifact.getVersion();
String qualifier = formatDate(timestamp, true) + '-' + buildNumber;
version = version.substring(0, version.length() - SNAPSHOT.length()) + qualifier;
return addSnapshotVersion(versioning, artifact.getExtension(), timestamp, version, buildNumber);
}
private static SnapshotVersion addSnapshotVersion(
Versioning versioning, String extension, Date timestamp, String version, int buildNumber) {
Snapshot snapshot = new Snapshot();
snapshot.setBuildNumber(buildNumber);
snapshot.setTimestamp(formatDate(timestamp, true));
SnapshotVersion sv = new SnapshotVersion();
sv.setExtension(extension);
sv.setVersion(version);
sv.setUpdated(formatDate(timestamp, false));
versioning.addSnapshotVersion(sv);
// make the new snapshot the current one
versioning.setSnapshot(snapshot);
versioning.setLastUpdatedTimestamp(timestamp);
return sv;
}
// the format written by Maven 2
// (https://maven.apache.org/ref/2.2.1/maven-repository-metadata/repository-metadata.html)
private static void addSnapshotVersionLegacy(Versioning versioning, Date timestamp, int buildNumber) {
Snapshot snapshot = new Snapshot();
snapshot.setBuildNumber(buildNumber);
snapshot.setTimestamp(formatDate(timestamp, true));
versioning.setSnapshot(snapshot);
versioning.setLastUpdatedTimestamp(timestamp);
}
/*-- END helper methods to populate metadata objects ---*/
}