Skip to content

Commit 310b450

Browse files
michelleqyunMichelle Yun
andauthored
Add changes to support upstream to maven google repo (#496)
* Add changes to support upstream to maven google repo * Address comments to remove puppeteersharp * Address comments to move away from upstream-specific implementation * Remove package absolute URI implementation * Address comments to add helper functions, exception handling, log messages * Consolidate directory index strategy into single method * Address comments * Pass exception to logger --------- Co-authored-by: Michelle Yun <[email protected]>
1 parent 414b6a5 commit 310b450

19 files changed

+2448
-186
lines changed
Lines changed: 61 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,61 @@
1+
// Copyright (c) Microsoft Corporation. Licensed under the MIT License.
2+
3+
using System;
4+
using System.ComponentModel;
5+
6+
namespace Microsoft.CST.OpenSource.Model.Enums;
7+
8+
/// <summary>
9+
/// Maven upstream repositories supported by OSSGadget.
10+
/// </summary>
11+
public enum MavenArtifactType
12+
{
13+
[Description(".aar")]
14+
Aar,
15+
16+
[Description("-client.jar")]
17+
ClientJar,
18+
19+
[Description(".ear")]
20+
Ear,
21+
22+
[Description("-javadoc.jar")]
23+
JavadocJar,
24+
25+
[Description(".pom")]
26+
Pom,
27+
28+
[Description(".rar")]
29+
Rar,
30+
31+
[Description("-sources.jar")]
32+
SourcesJar,
33+
34+
[Description("-tests.jar")]
35+
TestsJar,
36+
37+
[Description("-tests-sources.jar")]
38+
TestSourcesJar,
39+
40+
[Description(".war")]
41+
War,
42+
43+
[Description(".jar")]
44+
Jar,
45+
46+
Unknown,
47+
}
48+
49+
/// <summary>
50+
/// Extension methods for <see cref="MavenArtifactType"/>.
51+
/// </summary>
52+
public static class MavenArtifactTypeExtensions
53+
{
54+
public static string GetTypeNameExtension(this MavenArtifactType type)
55+
{
56+
var fieldInfo = type.GetType().GetField(type.ToString());
57+
var attributes = (DescriptionAttribute[])fieldInfo.GetCustomAttributes(typeof(DescriptionAttribute), false);
58+
59+
return attributes.Length > 0 ? attributes[0].Description : string.Empty;
60+
}
61+
}

src/Shared/PackageManagers/MavenProjectManager.cs

Lines changed: 281 additions & 103 deletions
Large diffs are not rendered by default.

src/oss-tests/ProjectManagerTests/MavenProjectManagerTests.cs

Lines changed: 108 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -3,38 +3,52 @@
33
namespace Microsoft.CST.OpenSource.Tests.ProjectManagerTests
44
{
55
using Microsoft.CST.OpenSource.Extensions;
6+
using Microsoft.CST.OpenSource.Model.Enums;
67
using Model;
78
using Moq;
8-
using Octokit;
99
using oss;
1010
using PackageActions;
1111
using PackageManagers;
1212
using PackageUrl;
1313
using RichardSzalay.MockHttp;
14+
using System;
1415
using System.Collections.Generic;
1516
using System.Collections.Immutable;
1617
using System.Linq;
1718
using System.Net;
1819
using System.Net.Http;
20+
using System.Text;
1921
using System.Threading.Tasks;
2022
using VisualStudio.TestTools.UnitTesting;
2123

2224
[TestClass]
2325
public class MavenProjectManagerTests
2426
{
27+
public const string DEFAULT_MAVEN_ENDPOINT = "https://repo1.maven.org/maven2";
28+
public const string GOOGLE_MAVEN_ENDPOINT = "https://maven.google.com";
29+
2530
private readonly Mock<MavenProjectManager> _projectManager;
2631
private readonly IHttpClientFactory _httpFactory;
2732

2833
private readonly IDictionary<string, string> _packages = new Dictionary<string, string>()
2934
{
30-
{ "https://repo1.maven.org/maven2/ant/ant/1.6/", Resources.maven_ant_1_6_html },
3135
{ "https://repo1.maven.org/maven2/ant/ant/", Resources.maven_ant_all_html },
3236
{ "https://repo1.maven.org/maven2/ant/ant/maven-metadata.xml", Resources.maven_ant_metadata_xml },
37+
{ "https://repo1.maven.org/maven2/ant/ant/1.6/", Resources.maven_ant_1_6_html },
3338
{ "https://repo1.maven.org/maven2/ant/ant/1.6/ant-1.6.pom", Resources.maven_ant_1_6_pom },
34-
{ "https://repo1.maven.org/maven2/com/microsoft/fluentui/fluentui_listitem/0.0.8/", Resources.maven_microsoft_fluentui_listitem_0_0_8_html },
35-
{ "https://repo1.maven.org/maven2/com/microsoft/fluentui/fluentui_listitem/", Resources.maven_microsoft_fluentui_listitem_all_html },
36-
{ "https://repo1.maven.org/maven2/com/microsoft/fluentui/fluentui_listitem/maven-metadata.xml", Resources.maven_microsoft_fluentui_listitem_metadata_xml },
39+
{ "https://repo1.maven.org/maven2/com/microsoft/fluentui/fluentui_listitem/", Resources.maven_fluentui_listitem_all_html },
40+
{ "https://repo1.maven.org/maven2/com/microsoft/fluentui/fluentui_listitem/maven-metadata.xml", Resources.maven_fluentui_listitem_metadata_xml },
41+
{ "https://repo1.maven.org/maven2/com/microsoft/fluentui/fluentui_listitem/0.0.8/", Resources.maven_fluentui_listitem_0_0_8_html },
3742
{ "https://repo1.maven.org/maven2/com/microsoft/fluentui/fluentui_listitem/0.0.8/fluentui_listitem-0.0.8.pom", Resources.maven_fluentui_listitem_0_0_8_pom },
43+
{ "https://maven.google.com/android/arch/core/core/maven-metadata.xml", Resources.maven_core_metadata_xml },
44+
{ "https://maven.google.com/android/arch/core/core/1.0.0-alpha2/core-1.0.0-alpha2.aar", Resources.maven_core_1_0_0_alpha2_aar },
45+
{ "https://maven.google.com/android/arch/core/core/1.0.0-alpha2/core-1.0.0-alpha2.pom", Resources.maven_core_1_0_0_alpha2_pom },
46+
{ "https://maven.google.com/android/arch/core/core/1.0.0-alpha2/core-1.0.0-alpha2-sources.jar", Resources.maven_core_1_0_0_alpha2_sources_jar },
47+
{ "https://maven.google.com/com/google/cose/cose/maven-metadata.xml", Resources.maven_cose_metadata_xml },
48+
{ "https://maven.google.com/com/google/cose/cose/20230908/cose-20230908.pom", Resources.maven_cose_20230908_pom },
49+
{ "https://maven.google.com/com/google/cose/cose/20230908/cose-20230908.jar", Resources.maven_cose_20230908_jar },
50+
{ "https://maven.google.com/com/google/cose/cose/20230908/cose-20230908-javadoc.jar", Resources.maven_cose_20230908_javadoc_jar },
51+
{ "https://maven.google.com/com/google/cose/cose/20230908/artifact-metadata.json", Resources.maven_cose_20230908_artifact_metadata_json },
3852
}.ToImmutableDictionary();
3953

4054
public MavenProjectManagerTests()
@@ -47,6 +61,16 @@ public MavenProjectManagerTests()
4761
{
4862
MockHttpFetchResponse(HttpStatusCode.OK, url, json, mockHttp);
4963
}
64+
mockHttp.When(HttpMethod.Get, "https://maven.google.com/android/arch/core/core/1.0.0-alpha2/core-1.0.0-alpha2-client.jar").Respond(HttpStatusCode.NotFound);
65+
mockHttp.When(HttpMethod.Get, "https://maven.google.com/android/arch/core/core/1.0.0-alpha2/core-1.0.0-alpha2.ear").Respond(HttpStatusCode.NotFound);
66+
mockHttp.When(HttpMethod.Get, "https://maven.google.com/android/arch/core/core/1.0.0-alpha2/core-1.0.0-alpha2-javadoc.jar").Respond(HttpStatusCode.NotFound);
67+
mockHttp.When(HttpMethod.Get, "https://maven.google.com/android/arch/core/core/1.0.0-alpha2/core-1.0.0-alpha2.rar").Respond(HttpStatusCode.NotFound);
68+
mockHttp.When(HttpMethod.Get, "https://maven.google.com/android/arch/core/core/1.0.0-alpha2/core-1.0.0-alpha2-tests.jar").Respond(HttpStatusCode.NotFound);
69+
mockHttp.When(HttpMethod.Get, "https://maven.google.com/android/arch/core/core/1.0.0-alpha2/core-1.0.0-alpha2-tests-sources.jar").Respond(HttpStatusCode.NotFound);
70+
mockHttp.When(HttpMethod.Get, "https://maven.google.com/android/arch/core/core/1.0.0-alpha2/core-1.0.0-alpha2.war").Respond(HttpStatusCode.NotFound);
71+
mockHttp.When(HttpMethod.Get, "https://maven.google.com/android/arch/core/core/1.0.0-alpha2/core-1.0.0-alpha2.jar").Respond(HttpStatusCode.NotFound);
72+
mockHttp.When(HttpMethod.Get, "https://maven.google.com/android/arch/core/core/").Respond(HttpStatusCode.NotFound);
73+
mockHttp.When(HttpMethod.Get, "https://maven.google.com/com/google/cose/cose/").Respond(HttpStatusCode.NotFound);
5074

5175
mockFactory.Setup(_ => _.CreateClient(It.IsAny<string>())).Returns(mockHttp.ToHttpClient());
5276
_httpFactory = mockFactory.Object;
@@ -56,35 +80,67 @@ public MavenProjectManagerTests()
5680

5781
[DataTestMethod]
5882
[DataRow("pkg:maven/ant/[email protected]?repository_url=https://repo1.maven.org/maven2", "https://repo1.maven.org/maven2/ant/ant/1.6/")]
59-
public async Task GetArtifactDownloadUrisSucceeds_Async(string purlString, string expectedUriPrefix)
83+
public async Task MavenCentral_GetArtifactDownloadUrisSucceeds_Async(string purlString, string expectedUriPrefix)
6084
{
6185
PackageURL purl = new(purlString);
62-
List<ArtifactUri<MavenProjectManager.MavenArtifactType>> uris = await _projectManager.Object.GetArtifactDownloadUrisAsync(purl).ToListAsync();
86+
List<ArtifactUri<MavenArtifactType>> uris = await _projectManager.Object.GetArtifactDownloadUrisAsync(purl).ToListAsync();
6387

64-
Assert.IsNotNull(uris.SingleOrDefault(artifact => artifact.Type == MavenProjectManager.MavenArtifactType.Jar
65-
&& artifact.Uri == new System.Uri(expectedUriPrefix + $"{purl.Name}-{purl.Version}.jar")));
66-
Assert.IsNotNull(uris.SingleOrDefault(artifact => artifact.Type == MavenProjectManager.MavenArtifactType.SourcesJar
88+
Assert.IsNotNull(uris.SingleOrDefault(artifact => artifact.Type == MavenArtifactType.Jar
89+
&& artifact.Uri == new System.Uri(expectedUriPrefix + $"{purl.Name}-{purl.Version}.jar")));
90+
Assert.IsNotNull(uris.SingleOrDefault(artifact => artifact.Type == MavenArtifactType.SourcesJar
6791
&& artifact.Uri == new System.Uri(expectedUriPrefix + $"{purl.Name}-{purl.Version}-sources.jar")));
68-
Assert.IsNotNull(uris.SingleOrDefault(artifact => artifact.Type == MavenProjectManager.MavenArtifactType.Pom
92+
Assert.IsNotNull(uris.SingleOrDefault(artifact => artifact.Type == MavenArtifactType.Pom
93+
&& artifact.Uri == new System.Uri(expectedUriPrefix + $"{purl.Name}-{purl.Version}.pom")));
94+
}
95+
96+
[DataTestMethod]
97+
[DataRow("pkg:maven/android.arch.core/[email protected]?repository_url=https://maven.google.com", "https://maven.google.com/android/arch/core/core/1.0.0-alpha2/")]
98+
public async Task GoogleMaven_Core_GetArtifactDownloadUrisSucceeds_Async(string purlString, string expectedUriPrefix)
99+
{
100+
PackageURL purl = new(purlString);
101+
List<ArtifactUri<MavenArtifactType>> uris = await _projectManager.Object.GetArtifactDownloadUrisAsync(purl).ToListAsync();
102+
103+
Assert.IsNotNull(uris.SingleOrDefault(artifact => artifact.Type == MavenArtifactType.Pom
104+
&& artifact.Uri == new System.Uri(expectedUriPrefix + $"{purl.Name}-{purl.Version}.pom")));
105+
Assert.IsNotNull(uris.SingleOrDefault(artifact => artifact.Type == MavenArtifactType.Aar
106+
&& artifact.Uri == new System.Uri(expectedUriPrefix + $"{purl.Name}-{purl.Version}.aar")));
107+
}
108+
109+
[DataTestMethod]
110+
[DataRow("pkg:maven/com.google.cose/cose@20230908?repository_url=https://maven.google.com", "https://maven.google.com/com/google/cose/cose/20230908/")]
111+
public async Task GoogleMaven_Cose_GetArtifactDownloadUrisSucceeds_Async(string purlString, string expectedUriPrefix)
112+
{
113+
PackageURL purl = new(purlString);
114+
List<ArtifactUri<MavenArtifactType>> uris = await _projectManager.Object.GetArtifactDownloadUrisAsync(purl).ToListAsync();
115+
116+
Assert.IsNotNull(uris.SingleOrDefault(artifact => artifact.Type == MavenArtifactType.Jar
117+
&& artifact.Uri == new System.Uri(expectedUriPrefix + $"{purl.Name}-{purl.Version}.jar")));
118+
Assert.IsNotNull(uris.SingleOrDefault(artifact => artifact.Type == MavenArtifactType.JavadocJar
119+
&& artifact.Uri == new System.Uri(expectedUriPrefix + $"{purl.Name}-{purl.Version}-javadoc.jar")));
120+
Assert.IsNotNull(uris.SingleOrDefault(artifact => artifact.Type == MavenArtifactType.Pom
69121
&& artifact.Uri == new System.Uri(expectedUriPrefix + $"{purl.Name}-{purl.Version}.pom")));
70122
}
71123

72124
[DataTestMethod]
73125
[DataRow("pkg:maven/ant/[email protected]?repository_url=https://repo1.maven.org/maven2")] // Normal package
126+
[DataRow("pkg:maven/android.arch.core/[email protected]?repository_url=https://maven.google.com")]
127+
[DataRow("pkg:maven/com.google.cose/cose@20230908?repository_url=https://maven.google.com")]
74128
public async Task MetadataSucceeds(string purlString)
75129
{
76130
PackageURL purl = new(purlString);
77131
PackageMetadata? metadata = await _projectManager.Object.GetPackageMetadataAsync(purl, useCache: false);
78-
132+
79133
Assert.IsNotNull(metadata);
80134
Assert.AreEqual(purl.GetFullName(), metadata.Name);
81135
Assert.AreEqual(purl.Version, metadata.PackageVersion);
82136
Assert.IsNotNull(metadata.UploadTime);
83137
}
84138

85139
[DataTestMethod]
86-
[DataRow("pkg:maven/ant/[email protected]", 13, "1.7.0")]
87-
[DataRow("pkg:maven/com.microsoft.fluentui/[email protected]", 21, "0.1.6")]
140+
[DataRow("pkg:maven/ant/[email protected]", 12, "1.6.5")]
141+
[DataRow("pkg:maven/com.microsoft.fluentui/[email protected]", 31, "0.3.4")]
142+
[DataRow("pkg:maven/android.arch.core/[email protected]?repository_url=https://maven.google.com", 3, "1.0.0-alpha3")]
143+
[DataRow("pkg:maven/com.google.cose/cose@20230908?repository_url=https://maven.google.com", 1, "20230908")]
88144
public async Task EnumerateVersionsSucceeds(string purlString, int count, string latestVersion)
89145
{
90146
PackageURL purl = new(purlString);
@@ -93,10 +149,24 @@ public async Task EnumerateVersionsSucceeds(string purlString, int count, string
93149
Assert.AreEqual(count, versions.Count);
94150
Assert.AreEqual(latestVersion, versions.First());
95151
}
96-
152+
97153
[DataTestMethod]
98154
[DataRow("pkg:maven/ant/[email protected]")]
99155
[DataRow("pkg:maven/com.microsoft.fluentui/[email protected]")]
156+
[DataRow("pkg:maven/android.arch.core/[email protected]?repository_url=https://maven.google.com")]
157+
[DataRow("pkg:maven/com.google.cose/cose@20230908?repository_url=https://maven.google.com")]
158+
public async Task PackageExistsAsyncSucceeds(string purlString)
159+
{
160+
PackageURL purl = new(purlString);
161+
162+
Assert.IsTrue(await _projectManager.Object.PackageExistsAsync(purl, useCache: false));
163+
}
164+
165+
[DataTestMethod]
166+
[DataRow("pkg:maven/ant/[email protected]")]
167+
[DataRow("pkg:maven/com.microsoft.fluentui/[email protected]")]
168+
[DataRow("pkg:maven/android.arch.core/[email protected]?repository_url=https://maven.google.com")]
169+
[DataRow("pkg:maven/com.google.cose/cose@20230908?repository_url=https://maven.google.com")]
100170
public async Task PackageVersionExistsAsyncSucceeds(string purlString)
101171
{
102172
PackageURL purl = new(purlString);
@@ -110,9 +180,29 @@ private static void MockHttpFetchResponse(
110180
string content,
111181
MockHttpMessageHandler httpMock)
112182
{
113-
httpMock
114-
.When(HttpMethod.Get, url)
115-
.Respond(statusCode, "application/json", content);
183+
if (url.EndsWith(".pom"))
184+
{
185+
string lastModified = DateTime.Parse("9/8/2023 4:21:38 PM").ToString("R");
186+
187+
httpMock
188+
.When(HttpMethod.Get, url)
189+
.Respond(req =>
190+
{
191+
var response = new HttpResponseMessage
192+
{
193+
StatusCode = statusCode,
194+
Content = new StringContent(content, Encoding.UTF8, "application/json")
195+
};
196+
response.Content.Headers.Add("Last-Modified", lastModified);
197+
return response;
198+
});
199+
}
200+
else
201+
{
202+
httpMock
203+
.When(HttpMethod.Get, url)
204+
.Respond(statusCode, "application/json", content);
205+
}
116206
}
117207
}
118208
}

0 commit comments

Comments
 (0)