Skip to content

Commit

Permalink
feat: Validate resource name uniqueness to provide readable errors
Browse files Browse the repository at this point in the history
Fixes #672.
  • Loading branch information
jskeet committed Sep 6, 2023
1 parent c1de3d2 commit 6a8f833
Show file tree
Hide file tree
Showing 3 changed files with 56 additions and 2 deletions.
8 changes: 8 additions & 0 deletions Google.Api.Generator.Tests/ProtoTest.cs
Original file line number Diff line number Diff line change
Expand Up @@ -324,5 +324,13 @@ public void PublishingSettings() => ProtoTestSingle(

[Fact]
public void BuildLro() => BuildTest("Lro");

[Fact]
public void DuplicateResourceDefinitions()
{
var exception = ProtoTestSingleFailure<InvalidOperationException>("DuplicateResourceDefinitions");
Assert.Contains("Multiple definitions", exception.Message);
Assert.Contains("TestResource", exception.Message);
}
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,30 @@
syntax = "proto3";

package testing.duplicateresourcedefinitions;

import "google/api/client.proto";
import "google/api/resource.proto";

// Deliberately define the same resource twice, to provoke an error.
option (google.api.resource_definition) = {
type: "test.googleapis.com/TestResource"
pattern: "projects/{project}"
};

option (google.api.resource_definition) = {
type: "test.googleapis.com/TestResource"
pattern: "organizations/{organization}"
};

service Basic {
option (google.api.default_host) = "basic.example.com";
option (google.api.oauth_scopes) = "scope1,scope2";

rpc AMethod(Request) returns(Response);
}

message Request {
}

message Response {
}
20 changes: 18 additions & 2 deletions Google.Api.Generator/ProtoUtils/ProtoCatalog.cs
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@
// limitations under the License.

using Google.Protobuf.Reflection;
using System;
using System.Collections.Generic;
using System.Collections.Immutable;
using System.Linq;
Expand Down Expand Up @@ -42,8 +43,10 @@ public ProtoCatalog(
_services = allDescriptors.SelectMany(desc => desc.Services).ToDictionary(x => x.FullName);
_resourcesByFileName = ResourceDetails.LoadResourceDefinitionsByFileName(allDescriptors, commonResourcesConfigs, librarySettings).GroupBy(x => x.FileName)
.ToImmutableDictionary(x => x.Key, x => (IReadOnlyList<ResourceDetails.Definition>)x.ToImmutableList());
var resourcesByUrt = _resourcesByFileName.Values.SelectMany(x => x).ToDictionary(x => x.UnifiedResourceTypeName);
var resourcesByPatternComparison = _resourcesByFileName.Values.SelectMany(x => x)
var allResources = _resourcesByFileName.Values.SelectMany(x => x);
ValidateUniqueResourceTypeNames();
var resourcesByUrt = allResources.ToDictionary(x => x.UnifiedResourceTypeName);
var resourcesByPatternComparison = allResources
.SelectMany(def => def.Patterns.Where(x => !x.IsWildcard).Select(x => (x.Template.ParentComparisonString, def)))
.GroupBy(x => x.ParentComparisonString, x => x.def)
.ToImmutableDictionary(x => x.Key, x => (IReadOnlyList<ResourceDetails.Definition>)x.ToImmutableList());
Expand All @@ -57,6 +60,19 @@ public ProtoCatalog(
.ToDictionary(x => x.field.FullName, x => x.res);

IEnumerable<MessageDescriptor> MsgPlusNested(MessageDescriptor msgDesc) => msgDesc.NestedTypes.SelectMany(MsgPlusNested).Append(msgDesc);

void ValidateUniqueResourceTypeNames()
{
var multiDefinitions = allResources
.GroupBy(x => x.UnifiedResourceTypeName)
.Where(g => g.Count() > 1)
.Select(g => g.Key)
.ToList();
if (multiDefinitions.Any())
{
throw new InvalidOperationException($"Multiple definitions found for the following resources: {string.Join(",", multiDefinitions)}");
}
}
}

private readonly string _defaultPackage;
Expand Down

0 comments on commit 6a8f833

Please sign in to comment.