]> source.dussan.org Git - archiva.git/commitdiff
[MRM-161] report on metadata
authorBrett Porter <brett@apache.org>
Fri, 8 Sep 2006 07:52:21 +0000 (07:52 +0000)
committerBrett Porter <brett@apache.org>
Fri, 8 Sep 2006 07:52:21 +0000 (07:52 +0000)
git-svn-id: https://svn.apache.org/repos/asf/maven/archiva/trunk@441419 13f79535-47bb-0310-9956-ffa450edef68

archiva-core/src/main/java/org/apache/maven/archiva/scheduler/task/IndexerTask.java
archiva-discoverer/src/main/java/org/apache/maven/archiva/discoverer/DefaultMetadataDiscoverer.java
archiva-discoverer/src/main/java/org/apache/maven/archiva/discoverer/MetadataDiscoverer.java
archiva-discoverer/src/main/java/org/apache/maven/archiva/discoverer/filter/AcceptAllMetadataFilter.java [new file with mode: 0644]
archiva-discoverer/src/main/java/org/apache/maven/archiva/discoverer/filter/MetadataFilter.java [new file with mode: 0644]
archiva-reports-standard/pom.xml
archiva-reports-standard/src/main/java/org/apache/maven/archiva/reporting/BadMetadataReportProcessor.java
archiva-reports-standard/src/main/java/org/apache/maven/archiva/reporting/ReportingDatabase.java
archiva-reports-standard/src/main/java/org/apache/maven/archiva/reporting/ReportingMetadataFilter.java [new file with mode: 0644]
archiva-reports-standard/src/main/mdo/reporting.mdo
archiva-reports-standard/src/test/java/org/apache/maven/archiva/reporting/BadMetadataReportProcessorTest.java

index 94d4aba387868586a4064c26dc1153a05a4f0bf6..d725c1931ef26ead5b6bee27702a7a1ee1226164 100644 (file)
@@ -24,6 +24,7 @@ import org.apache.maven.archiva.configuration.RepositoryConfiguration;
 import org.apache.maven.archiva.discoverer.ArtifactDiscoverer;
 import org.apache.maven.archiva.discoverer.DiscovererException;
 import org.apache.maven.archiva.discoverer.MetadataDiscoverer;
+import org.apache.maven.archiva.discoverer.filter.MetadataFilter;
 import org.apache.maven.archiva.discoverer.filter.SnapshotArtifactFilter;
 import org.apache.maven.archiva.indexer.RepositoryArtifactIndex;
 import org.apache.maven.archiva.indexer.RepositoryArtifactIndexFactory;
@@ -31,13 +32,16 @@ import org.apache.maven.archiva.indexer.RepositoryIndexException;
 import org.apache.maven.archiva.indexer.record.IndexRecordExistsArtifactFilter;
 import org.apache.maven.archiva.indexer.record.RepositoryIndexRecordFactory;
 import org.apache.maven.archiva.reporting.ArtifactReportProcessor;
+import org.apache.maven.archiva.reporting.MetadataReportProcessor;
 import org.apache.maven.archiva.reporting.ReportingDatabase;
+import org.apache.maven.archiva.reporting.ReportingMetadataFilter;
 import org.apache.maven.archiva.reporting.ReportingStore;
 import org.apache.maven.archiva.reporting.ReportingStoreException;
 import org.apache.maven.archiva.scheduler.TaskExecutionException;
 import org.apache.maven.artifact.Artifact;
 import org.apache.maven.artifact.factory.ArtifactFactory;
 import org.apache.maven.artifact.repository.ArtifactRepository;
+import org.apache.maven.artifact.repository.metadata.RepositoryMetadata;
 import org.apache.maven.artifact.resolver.filter.AndArtifactFilter;
 import org.apache.maven.model.Model;
 import org.apache.maven.project.MavenProject;
@@ -209,6 +213,10 @@ public class IndexerTask
                             // run the reports
                             runArtifactReports( currentArtifacts, reporter );
 
+                            // store intermittently because if anything crashes out after indexing then we will have
+                            // lost track of these artifact's reports
+                            reportingStore.storeReports( reporter, repository );
+
                             index.indexArtifacts( currentArtifacts, recordFactory );
                         }
 
@@ -217,12 +225,20 @@ public class IndexerTask
                         flushProjectBuilderCacheHack();
                     }
 
-                    // TODO! use reporting manager as a filter
+                    MetadataFilter metadataFilter = new ReportingMetadataFilter( reporter );
+
                     MetadataDiscoverer metadataDiscoverer =
                         (MetadataDiscoverer) metadataDiscoverers.get( layoutProperty );
-                    metadataDiscoverer.discoverMetadata( repository, blacklistedPatterns );
+                    List metadata =
+                        metadataDiscoverer.discoverMetadata( repository, blacklistedPatterns, metadataFilter );
 
-                    //TODO! metadata reporting
+                    if ( !metadata.isEmpty() )
+                    {
+                        getLogger().info( "Discovered " + metadata.size() + " unprocessed metadata files" );
+
+                        // run the reports
+                        runMetadataReports( metadata, repository, reporter );
+                    }
 
                     reportingStore.storeReports( reporter, repository );
                 }
@@ -245,6 +261,32 @@ public class IndexerTask
         getLogger().info( "Finished repository indexing process in " + time + "ms" );
     }
 
+    private void runMetadataReports( List metadata, ArtifactRepository repository, ReportingDatabase reporter )
+    {
+        for ( Iterator i = metadata.iterator(); i.hasNext(); )
+        {
+            RepositoryMetadata repositoryMetadata = (RepositoryMetadata) i.next();
+
+            File file =
+                new File( repository.getBasedir(), repository.pathOfRemoteRepositoryMetadata( repositoryMetadata ) );
+            reporter.cleanMetadata( repositoryMetadata, file.lastModified() );
+
+            // TODO: should the report set be limitable by configuration?
+            runMetadataReports( repositoryMetadata, repository, reporter );
+        }
+    }
+
+    private void runMetadataReports( RepositoryMetadata repositoryMetadata, ArtifactRepository repository,
+                                     ReportingDatabase reporter )
+    {
+        for ( Iterator i = metadataReports.iterator(); i.hasNext(); )
+        {
+            MetadataReportProcessor report = (MetadataReportProcessor) i.next();
+
+            report.processMetadata( repositoryMetadata, repository, reporter );
+        }
+    }
+
     private void runArtifactReports( List artifacts, ReportingDatabase reporter )
     {
         for ( Iterator i = artifacts.iterator(); i.hasNext(); )
@@ -268,6 +310,9 @@ public class IndexerTask
             {
                 reporter.addWarning( artifact, "Error reading project model: " + e );
             }
+
+            reporter.removeArtifact( artifact );
+
             runArtifactReports( artifact, model, reporter );
         }
     }
index 77bbb1932de574edb745addda7bcfb5ef758e245..87a0bea2788bea43a4e94e32f4a7c1a4bad5c217 100644 (file)
@@ -16,6 +16,8 @@ package org.apache.maven.archiva.discoverer;
  * limitations under the License.
  */
 
+import org.apache.maven.archiva.discoverer.filter.AcceptAllMetadataFilter;
+import org.apache.maven.archiva.discoverer.filter.MetadataFilter;
 import org.apache.maven.artifact.Artifact;
 import org.apache.maven.artifact.repository.ArtifactRepository;
 import org.apache.maven.artifact.repository.metadata.ArtifactRepositoryMetadata;
@@ -28,12 +30,9 @@ import org.codehaus.plexus.util.StringUtils;
 import org.codehaus.plexus.util.xml.pull.XmlPullParserException;
 
 import java.io.File;
+import java.io.FileReader;
 import java.io.IOException;
-import java.io.InputStream;
-import java.io.InputStreamReader;
 import java.io.Reader;
-import java.net.MalformedURLException;
-import java.net.URL;
 import java.util.ArrayList;
 import java.util.Collections;
 import java.util.Iterator;
@@ -58,7 +57,7 @@ public class DefaultMetadataDiscoverer
      */
     private static final String[] STANDARD_DISCOVERY_INCLUDES = {"**/maven-metadata.xml"};
 
-    public List discoverMetadata( ArtifactRepository repository, List blacklistedPatterns )
+    public List discoverMetadata( ArtifactRepository repository, List blacklistedPatterns, MetadataFilter filter )
         throws DiscovererException
     {
         if ( !"file".equals( repository.getProtocol() ) )
@@ -76,7 +75,15 @@ public class DefaultMetadataDiscoverer
             try
             {
                 RepositoryMetadata metadata = buildMetadata( repository.getBasedir(), metadataPath );
-                metadataFiles.add( metadata );
+                File f = new File( repository.getBasedir(), metadataPath );
+                if ( filter.include( metadata, f.lastModified() ) )
+                {
+                    metadataFiles.add( metadata );
+                }
+                else
+                {
+                    addExcludedPath( metadataPath, "Metadata excluded by filter" );
+                }
             }
             catch ( DiscovererException e )
             {
@@ -87,33 +94,31 @@ public class DefaultMetadataDiscoverer
         return metadataFiles;
     }
 
+    public List discoverMetadata( ArtifactRepository repository, List blacklistedPatterns )
+        throws DiscovererException
+    {
+        return discoverMetadata( repository, blacklistedPatterns, new AcceptAllMetadataFilter() );
+    }
+
     private RepositoryMetadata buildMetadata( String repo, String metadataPath )
         throws DiscovererException
     {
         Metadata m;
-        String repoPath = repo + "/" + metadataPath;
+        File f = new File( repo, metadataPath );
         try
         {
-            URL url = new File( repoPath ).toURI().toURL();
-            InputStream is = url.openStream();
-            Reader reader = new InputStreamReader( is );
+            Reader reader = new FileReader( f );
             MetadataXpp3Reader metadataReader = new MetadataXpp3Reader();
 
             m = metadataReader.read( reader );
         }
         catch ( XmlPullParserException e )
         {
-            throw new DiscovererException( "Error parsing metadata file '" + repoPath + "': " + e.getMessage(), e );
-        }
-        catch ( MalformedURLException e )
-        {
-            // shouldn't happen
-            throw new DiscovererException( "Error constructing metadata file '" + repoPath + "': " + e.getMessage(),
-                                           e );
+            throw new DiscovererException( "Error parsing metadata file '" + f + "': " + e.getMessage(), e );
         }
         catch ( IOException e )
         {
-            throw new DiscovererException( "Error reading metadata file '" + repoPath + "': " + e.getMessage(), e );
+            throw new DiscovererException( "Error reading metadata file '" + f + "': " + e.getMessage(), e );
         }
 
         RepositoryMetadata repositoryMetadata = buildMetadata( m, metadataPath );
index 01243ad84f9ff0e197419b62aabe0ebdda685b31..ff5879f2d6f328d04d66419f1cb8a8389e6bdd55 100644 (file)
@@ -16,6 +16,7 @@ package org.apache.maven.archiva.discoverer;
  * limitations under the License.
  */
 
+import org.apache.maven.archiva.discoverer.filter.MetadataFilter;
 import org.apache.maven.artifact.repository.ArtifactRepository;
 
 import java.util.List;
@@ -28,6 +29,18 @@ public interface MetadataDiscoverer
 {
     String ROLE = MetadataDiscoverer.class.getName();
 
+    /**
+     * Search for metadata files in the repository.
+     *
+     * @param repository          The repository.
+     * @param blacklistedPatterns Patterns that are to be excluded from the discovery process.
+     * @param metadataFilter      filter to use on the discovered metadata before returning
+     * @return the list of artifacts found
+     * @throws DiscovererException if there is a problem during the discovery process
+     */
+    List discoverMetadata( ArtifactRepository repository, List blacklistedPatterns, MetadataFilter metadataFilter )
+        throws DiscovererException;
+
     /**
      * Search for metadata files in the repository.
      *
diff --git a/archiva-discoverer/src/main/java/org/apache/maven/archiva/discoverer/filter/AcceptAllMetadataFilter.java b/archiva-discoverer/src/main/java/org/apache/maven/archiva/discoverer/filter/AcceptAllMetadataFilter.java
new file mode 100644 (file)
index 0000000..bed3efd
--- /dev/null
@@ -0,0 +1,31 @@
+package org.apache.maven.archiva.discoverer.filter;
+
+/*
+ * Copyright 2005-2006 The Apache Software Foundation.
+ *
+ * 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.
+ */
+
+import org.apache.maven.artifact.repository.metadata.RepositoryMetadata;
+
+/**
+ * Filter that accepts all.
+ */
+public class AcceptAllMetadataFilter
+    implements MetadataFilter
+{
+    public boolean include( RepositoryMetadata metadata, long timestamp )
+    {
+        return true;
+    }
+}
diff --git a/archiva-discoverer/src/main/java/org/apache/maven/archiva/discoverer/filter/MetadataFilter.java b/archiva-discoverer/src/main/java/org/apache/maven/archiva/discoverer/filter/MetadataFilter.java
new file mode 100644 (file)
index 0000000..2c9b6b3
--- /dev/null
@@ -0,0 +1,36 @@
+package org.apache.maven.archiva.discoverer.filter;
+
+/*
+ * Copyright 2005-2006 The Apache Software Foundation.
+ *
+ * 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.
+ */
+
+import org.apache.maven.artifact.repository.metadata.RepositoryMetadata;
+
+/**
+ * Ability to filter repository metadata lists.
+ *
+ * @todo should be in maven-artifact
+ */
+public interface MetadataFilter
+{
+    /**
+     * Whether to include this metadata in the filtered list.
+     *
+     * @param metadata  the metadata
+     * @param timestamp the time to compare against - it will be included if it doesn't exist or is outdated
+     * @return whether to include it
+     */
+    boolean include( RepositoryMetadata metadata, long timestamp );
+}
index 3ee54d169626ee545207dd8cade4f437e512d184..da0737a8ef1f11cfa61e2a26fe2ed0faa9427b13 100755 (executable)
       <groupId>org.apache.maven.archiva</groupId>
       <artifactId>archiva-indexer</artifactId>
     </dependency>
+    <dependency>
+      <groupId>org.apache.maven.archiva</groupId>
+      <artifactId>archiva-discoverer</artifactId>
+    </dependency>
   </dependencies>
   <build>
     <plugins>
index ae22e0a9e5d9b449684da4f58ff1e647d8ec1ee4..354b67b76b010d4fac513e0f26d487aaa3872754 100644 (file)
@@ -32,6 +32,7 @@ import java.io.File;
 import java.io.IOException;
 import java.util.ArrayList;
 import java.util.Arrays;
+import java.util.Collections;
 import java.util.HashMap;
 import java.util.Iterator;
 import java.util.List;
@@ -79,8 +80,17 @@ public class BadMetadataReportProcessor
         }
         else
         {
-            String lastUpdated = metadata.getMetadata().getVersioning().getLastUpdated();
-            if ( lastUpdated == null || lastUpdated.length() == 0 )
+            Versioning versioning = metadata.getMetadata().getVersioning();
+            boolean found = false;
+            if ( versioning != null )
+            {
+                String lastUpdated = versioning.getLastUpdated();
+                if ( lastUpdated != null && lastUpdated.length() != 0 )
+                {
+                    found = true;
+                }
+            }
+            if ( !found )
             {
                 reporter.addFailure( metadata, "Missing lastUpdated element inside the metadata." );
             }
@@ -215,17 +225,20 @@ public class BadMetadataReportProcessor
             repositoryQueryLayerFactory.createRepositoryQueryLayer( repository );
 
         Versioning versioning = metadata.getMetadata().getVersioning();
-        for ( Iterator versions = versioning.getVersions().iterator(); versions.hasNext(); )
+        if ( versioning != null )
         {
-            String version = (String) versions.next();
+            for ( Iterator versions = versioning.getVersions().iterator(); versions.hasNext(); )
+            {
+                String version = (String) versions.next();
 
-            Artifact artifact =
-                artifactFactory.createProjectArtifact( metadata.getGroupId(), metadata.getArtifactId(), version );
+                Artifact artifact =
+                    artifactFactory.createProjectArtifact( metadata.getGroupId(), metadata.getArtifactId(), version );
 
-            if ( !repositoryQueryLayer.containsArtifact( artifact ) )
-            {
-                reporter.addFailure( metadata, "Artifact version " + version + " is present in metadata but " +
-                    "missing in the repository." );
+                if ( !repositoryQueryLayer.containsArtifact( artifact ) )
+                {
+                    reporter.addFailure( metadata, "Artifact version " + version + " is present in metadata but " +
+                        "missing in the repository." );
+                }
             }
         }
     }
@@ -243,6 +256,7 @@ public class BadMetadataReportProcessor
         throws IOException
     {
         Versioning versioning = metadata.getMetadata().getVersioning();
+        List metadataVersions = versioning != null ? versioning.getVersions() : Collections.EMPTY_LIST;
         File versionsDir =
             new File( repository.getBasedir(), repository.pathOfRemoteRepositoryMetadata( metadata ) ).getParentFile();
         List versions = FileUtils.getFileNames( versionsDir, "*/*.pom", null, false );
@@ -250,7 +264,7 @@ public class BadMetadataReportProcessor
         {
             File path = new File( (String) i.next() );
             String version = path.getParentFile().getName();
-            if ( !versioning.getVersions().contains( version ) )
+            if ( !metadataVersions.contains( version ) )
             {
                 reporter.addFailure( metadata, "Artifact version " + version + " found in the repository but " +
                     "missing in the metadata." );
index 0b17f1ab5155dd88ad0faba49dacf71eb59c20d3..d50f16be4fb9e47c475d0f34f477d6fd6fd222d1 100644 (file)
@@ -125,39 +125,18 @@ public class ReportingDatabase
 
     public void addFailure( RepositoryMetadata metadata, String reason )
     {
-        MetadataResults results = getMetadataResults( metadata );
+        MetadataResults results = getMetadataResults( metadata, System.currentTimeMillis() );
         results.addFailure( createResults( reason ) );
         totalFailures++;
     }
 
     public void addWarning( RepositoryMetadata metadata, String reason )
     {
-        MetadataResults results = getMetadataResults( metadata );
+        MetadataResults results = getMetadataResults( metadata, System.currentTimeMillis() );
         results.addWarning( createResults( reason ) );
         totalWarnings++;
     }
 
-    private MetadataResults getMetadataResults( RepositoryMetadata metadata )
-    {
-        Map metadataMap = getMetadataMap();
-
-        String key = getMetadataKey( metadata.getGroupId(), metadata.getArtifactId(), metadata.getBaseVersion() );
-
-        MetadataResults results = (MetadataResults) metadataMap.get( key );
-        if ( results == null )
-        {
-            results = new MetadataResults();
-            results.setArtifactId( metadata.getArtifactId() );
-            results.setGroupId( metadata.getGroupId() );
-            results.setVersion( metadata.getBaseVersion() );
-
-            metadataMap.put( key, results );
-            reporting.getMetadata().add( results );
-        }
-
-        return results;
-    }
-
     private Map getMetadataMap()
     {
         if ( metadataMap == null )
@@ -208,4 +187,71 @@ public class ReportingDatabase
     {
         return reporting.getMetadata().iterator();
     }
+
+    public boolean isMetadataUpToDate( RepositoryMetadata metadata, long timestamp )
+    {
+        String key = getMetadataKey( metadata );
+        Map map = getMetadataMap();
+        MetadataResults results = (MetadataResults) map.get( key );
+        return results != null && results.getLastModified() >= timestamp;
+    }
+
+    /**
+     * Make sure the metadata record exists, but remove any previous reports in preparation for adding new ones.
+     *
+     * @param metadata     the metadata
+     * @param lastModified the modification time of the file being tracked
+     */
+    public void cleanMetadata( RepositoryMetadata metadata, long lastModified )
+    {
+        MetadataResults results = getMetadataResults( metadata, lastModified );
+
+        results.setLastModified( lastModified );
+        results.getFailures().clear();
+        results.getWarnings().clear();
+    }
+
+    private MetadataResults getMetadataResults( RepositoryMetadata metadata, long lastModified )
+    {
+        String key = getMetadataKey( metadata );
+        Map metadataMap = getMetadataMap();
+        MetadataResults results = (MetadataResults) metadataMap.get( key );
+        if ( results == null )
+        {
+            results = new MetadataResults();
+            results.setArtifactId( metadata.getArtifactId() );
+            results.setGroupId( metadata.getGroupId() );
+            results.setVersion( metadata.getBaseVersion() );
+            results.setLastModified( lastModified );
+
+            metadataMap.put( key, results );
+            reporting.getMetadata().add( results );
+        }
+        return results;
+    }
+
+    private static String getMetadataKey( RepositoryMetadata metadata )
+    {
+        return getMetadataKey( metadata.getGroupId(), metadata.getArtifactId(), metadata.getBaseVersion() );
+    }
+
+    public void removeArtifact( Artifact artifact )
+    {
+        Map map = getArtifactMap();
+
+        String key = getArtifactKey( artifact.getGroupId(), artifact.getArtifactId(), artifact.getVersion(),
+                                     artifact.getType(), artifact.getClassifier() );
+        ArtifactResults results = (ArtifactResults) map.get( key );
+        if ( results != null )
+        {
+            for ( Iterator i = reporting.getArtifacts().iterator(); i.hasNext(); )
+            {
+                if ( results.equals( i.next() ) )
+                {
+                    i.remove();
+                }
+            }
+            map.remove( key );
+        }
+    }
 }
diff --git a/archiva-reports-standard/src/main/java/org/apache/maven/archiva/reporting/ReportingMetadataFilter.java b/archiva-reports-standard/src/main/java/org/apache/maven/archiva/reporting/ReportingMetadataFilter.java
new file mode 100644 (file)
index 0000000..9ef876c
--- /dev/null
@@ -0,0 +1,39 @@
+package org.apache.maven.archiva.reporting;
+
+/*
+ * Copyright 2005-2006 The Apache Software Foundation.
+ *
+ * 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.
+ */
+
+import org.apache.maven.archiva.discoverer.filter.MetadataFilter;
+import org.apache.maven.artifact.repository.metadata.RepositoryMetadata;
+
+/**
+ * Implementation of a reporting filter. Artifacts already in the database are ignored.
+ */
+public class ReportingMetadataFilter
+    implements MetadataFilter
+{
+    private final ReportingDatabase reporter;
+
+    public ReportingMetadataFilter( ReportingDatabase reporter )
+    {
+        this.reporter = reporter;
+    }
+
+    public boolean include( RepositoryMetadata metadata, long timestamp )
+    {
+        return !reporter.isMetadataUpToDate( metadata, timestamp );
+    }
+}
index 84c8f4011de9453b5ddbc30004d3535f30b995ec..a01032b947a5976a522a9182933b26fa3aafe67c 100644 (file)
             The version of the metadata in the result.
           </description>
         </field>
+        <field xml.attribute="true">
+          <name>lastModified</name>
+          <version>1.0.0</version>
+          <type>long</type>
+          <identity>true</identity>
+          <description>
+            The time that the metadata was last modified.
+          </description>
+        </field>
       </fields>
     </class>
     <class>
index 49ebe469add60e73635f18a016b3898b783b152d..4acec298294f21b755c20d4f0f4f92a69695ff09 100644 (file)
@@ -72,6 +72,33 @@ public class BadMetadataReportProcessorTest
         assertFalse( "check no more failures", failures.hasNext() );
     }
 
+    public void testMetadataMissingVersioning()
+    {
+        Artifact artifact = artifactFactory.createBuildArtifact( "groupId", "artifactId", "1.0-alpha-1", "type" );
+
+        RepositoryMetadata metadata = new ArtifactRepositoryMetadata( artifact, null );
+
+        badMetadataReportProcessor.processMetadata( metadata, repository, reporter );
+
+        Iterator failures = reporter.getMetadataIterator();
+        assertTrue( "check there is a failure", failures.hasNext() );
+        MetadataResults results = (MetadataResults) failures.next();
+        failures = results.getFailures().iterator();
+        assertTrue( "check there is a failure", failures.hasNext() );
+        assertMetadata( metadata, results );
+        Result result = (Result) failures.next();
+        assertEquals( "check reason", "Missing lastUpdated element inside the metadata.", result.getReason() );
+        result = (Result) failures.next();
+        assertEquals( "check reason",
+                      "Artifact version 1.0-alpha-1 found in the repository but missing in the metadata.",
+                      result.getReason() );
+        result = (Result) failures.next();
+        assertEquals( "check reason",
+                      "Artifact version 1.0-alpha-2 found in the repository but missing in the metadata.",
+                      result.getReason() );
+        assertFalse( "check no more failures", failures.hasNext() );
+    }
+
     public void testMetadataValidVersions()
     {
         Artifact artifact = artifactFactory.createBuildArtifact( "groupId", "artifactId", "1.0-alpha-1", "type" );