Skip to content

Commit

Permalink
Almost have Storage schema generating from swagger spec
Browse files Browse the repository at this point in the history
  • Loading branch information
Dan Schulte committed Apr 7, 2016
1 parent a8c0328 commit ffb8fa3
Show file tree
Hide file tree
Showing 6 changed files with 275 additions and 17 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -34,6 +34,10 @@
<WarningLevel>4</WarningLevel>
</PropertyGroup>
<ItemGroup>
<Reference Include="Newtonsoft.Json, Version=7.0.0.0, Culture=neutral, PublicKeyToken=30ad4fe6b2a6aeed, processorArchitecture=MSIL">
<HintPath>..\..\..\..\packages\Newtonsoft.Json.7.0.1\lib\net45\Newtonsoft.Json.dll</HintPath>
<Private>True</Private>
</Reference>
<Reference Include="System" />
<Reference Include="System.Core" />
<Reference Include="System.Xml.Linq" />
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,10 @@
// Licensed under the MIT License. See License.txt in the project root for license information.

using Microsoft.Rest.Generator.ClientModel;
using System;
using Microsoft.Rest.Generator.Utilities;
using Newtonsoft.Json.Linq;
using System.Linq;
using System.Threading.Tasks;
using Xunit;

namespace Microsoft.Rest.Generator.AzureResourceSchema.Tests
Expand All @@ -11,46 +14,142 @@ namespace Microsoft.Rest.Generator.AzureResourceSchema.Tests
public class AzureResourceSchemaCodeGeneratorTests
{
[Fact]
public void DescriptionThrowsException()
public void Description()
{
Assert.Equal("Azure Resource Schema generator", CreateGenerator().Description);
}

[Fact]
public void ImplementationFileExtensionThrowsException()
public void ImplementationFileExtension()
{
Assert.Equal(".json", CreateGenerator().ImplementationFileExtension);
}

[Fact]
public void NameThrowsException()
public void Name()
{
Assert.Equal("AzureResourceSchema", CreateGenerator().Name);
}

[Fact]
public void UsageInstructionsThrowsException()
public void UsageInstructionsWithNoOutputFileSetting()
{
Assert.Equal("MOCK USAGE INSTRUCTIONS", CreateGenerator().UsageInstructions);
AzureResourceSchemaCodeGenerator codeGen = CreateGenerator();
Assert.Equal("Your Azure Resource Schema can be found at " + codeGen.SchemaPath, codeGen.UsageInstructions);
}

[Fact]
public void GenerateThrowsException()
public void UsageInstructionsWithOutputFileSetting()
{
ServiceClient serviceClient = new ServiceClient();
Assert.Throws<NotImplementedException>(() => { CreateGenerator().Generate(serviceClient); });
Settings settings = new Settings()
{
OutputFileName = "spam.json"
};
AzureResourceSchemaCodeGenerator codeGen = CreateGenerator(settings);

Assert.Equal("Your Azure Resource Schema can be found at " + codeGen.SchemaPath, codeGen.UsageInstructions);
}

[Fact]
public async void GenerateWithEmptyServiceClient()
{
await TestGenerate(new string[0],
@"{
'id': 'http://schema.management.azure.com/schemas//Microsoft.Storage.json#',
'$schema': 'http://json-schema.org/draft-04/schema#',
'title': 'Microsoft.Storage',
'description': 'Microsoft Storage Resource Types',
'resourceDefinitions': { }
}");
}

[Fact]
public async void GenerateWithServiceClientWithOneType()
{
await TestGenerate(new string[]
{
"/subscriptions/{subscriptionId}/resourceGroups/{resourceGroupName}/providers/Mock.Provider/mockType"
},
@"{
'id': 'http://schema.management.azure.com/schemas//Microsoft.Storage.json#',
'$schema': 'http://json-schema.org/draft-04/schema#',
'title': 'Microsoft.Storage',
'description': 'Microsoft Storage Resource Types',
'resourceDefinitions': {
'mockType': {
}
}
}");
}

[Fact]
public async void GenerateWithServiceClientWithTwoTypes()
{
await TestGenerate(new string[]
{
"/subscriptions/{subscriptionId}/resourceGroups/{resourceGroupName}/providers/Mock.Provider/mockType1",
"/subscriptions/{subscriptionId}/resourceGroups/{resourceGroupName}/providers/Mock.Provider/mockType2"
},
@"{
'id': 'http://schema.management.azure.com/schemas//Microsoft.Storage.json#',
'$schema': 'http://json-schema.org/draft-04/schema#',
'title': 'Microsoft.Storage',
'description': 'Microsoft Storage Resource Types',
'resourceDefinitions': {
'mockType1': {
},
'mockType2': {
}
}
}");
}

[Fact]
public void NormalizeClientModelThrowsException()
public void NormalizeClientModelDoesNothing()
{
ServiceClient serviceClient = new ServiceClient();
Assert.Throws<NotImplementedException>(() => { CreateGenerator().NormalizeClientModel(serviceClient); });
CreateGenerator().NormalizeClientModel(serviceClient);

// Nothing happens
}

private static AzureResourceSchemaCodeGenerator CreateGenerator()
{
return new AzureResourceSchemaCodeGenerator(new Settings());
return CreateGenerator(new Settings());
}
private static AzureResourceSchemaCodeGenerator CreateGenerator(Settings settings)
{
return new AzureResourceSchemaCodeGenerator(settings);
}

private static async Task TestGenerate(string[] methodUrls, string expectedJsonString)
{
MemoryFileSystem fileSystem = new MemoryFileSystem();

Settings settings = new Settings();
settings.FileSystem = fileSystem;

ServiceClient serviceClient = new ServiceClient();
foreach(string methodUrl in methodUrls)
{
serviceClient.Methods.Add(new Method()
{
Url = methodUrl
});
}
await CreateGenerator(settings).Generate(serviceClient);

Assert.Equal(2, fileSystem.VirtualStore.Count);

string folderPath = fileSystem.VirtualStore.Keys.First();
Assert.Equal("Folder", fileSystem.VirtualStore[folderPath].ToString());

JObject expectedJSON = JObject.Parse(expectedJsonString);

string fileContents = fileSystem.VirtualStore[fileSystem.VirtualStore.Keys.Skip(1).First()].ToString();
JObject actualJson = JObject.Parse(fileContents);

Assert.Equal(expectedJSON, actualJson);
}
}
}
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
<?xml version="1.0" encoding="utf-8"?>
<packages>
<package id="Newtonsoft.Json" version="7.0.1" targetFramework="net452" />
<package id="xunit" version="2.1.0" targetFramework="net452" />
<package id="xunit.abstractions" version="2.0.0" targetFramework="net452" />
<package id="xunit.assert" version="2.1.0" targetFramework="net452" />
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,10 @@
<WarningLevel>4</WarningLevel>
</PropertyGroup>
<ItemGroup>
<Reference Include="Newtonsoft.Json, Version=7.0.0.0, Culture=neutral, PublicKeyToken=30ad4fe6b2a6aeed, processorArchitecture=MSIL">
<HintPath>..\..\..\..\packages\Newtonsoft.Json.7.0.1\lib\net45\Newtonsoft.Json.dll</HintPath>
<Private>True</Private>
</Reference>
<Reference Include="System" />
<Reference Include="System.Core" />
</ItemGroup>
Expand All @@ -44,5 +48,8 @@
<Link>CustomDictionary.xml</Link>
</CodeAnalysisDictionary>
</ItemGroup>
<ItemGroup>
<None Include="packages.config" />
</ItemGroup>
<Import Project="$(MSBuildToolsPath)\Microsoft.CSharp.targets" />
</Project>
Original file line number Diff line number Diff line change
Expand Up @@ -2,18 +2,33 @@
// Licensed under the MIT License. See License.txt in the project root for license information.

using Microsoft.Rest.Generator.ClientModel;
using Newtonsoft.Json;
using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Threading.Tasks;

namespace Microsoft.Rest.Generator.AzureResourceSchema
{
public class AzureResourceSchemaCodeGenerator : CodeGenerator
{
private const string resourceMethodPrefix = "/subscriptions/{subscriptionId}/resourceGroups/{resourceGroupName}/providers/";

public AzureResourceSchemaCodeGenerator(Settings settings)
: base(settings)
{
}

public string SchemaPath
{
get
{
string defaultSchemaFileName = Path.GetFileNameWithoutExtension(Settings.Input) + ".schema.json";
return Path.Combine(Settings.OutputDirectory, Settings.OutputFileName ?? defaultSchemaFileName);
}
}

public override string Description
{
get { return "Azure Resource Schema generator"; }
Expand All @@ -31,17 +46,145 @@ public override string Name

public override string UsageInstructions
{
get { return "MOCK USAGE INSTRUCTIONS"; }
get { return "Your Azure Resource Schema can be found at " + SchemaPath; }
}

public override Task Generate(ServiceClient serviceClient)
public override void NormalizeClientModel(ServiceClient serviceClient)
{
throw new NotImplementedException();
}

public override void NormalizeClientModel(ServiceClient serviceClient)
public override async Task Generate(ServiceClient serviceClient)
{
throw new NotImplementedException();
StringWriter stringWriter = new StringWriter();
using (JsonTextWriter writer = new JsonTextWriter(stringWriter))
{
writer.Formatting = Formatting.Indented;
writer.Indentation = 2;
writer.IndentChar = ' ';

string resourceProvider = GetResourceProvider(serviceClient);
IEnumerable<string> resourceFullTypes = GetResourceFullTypes(serviceClient);

WriteObject(writer, () => {
WriteProperty(writer, "id", string.Format("http://schema.management.azure.com/schemas/{0}/Microsoft.Storage.json#", serviceClient.ApiVersion));
WriteProperty(writer, "$schema", "http://json-schema.org/draft-04/schema#");
WriteProperty(writer, "title", resourceProvider);
WriteProperty(writer, "description", resourceProvider.Replace('.', ' ') + " Resource Types");
WriteProperty(writer, "resourceDefinitions", () => {
foreach (string resourceFullType in resourceFullTypes)
{
string resourceShortType = resourceFullType.Substring(resourceFullType.IndexOf('/') + 1);

WriteProperty(writer, resourceShortType, () => {
WriteProperty(writer, "type", "object");
WriteProperty(writer, "properties", () => {
WriteProperty(writer, "type", () => {
WriteProperty(writer, "enum", new string[] {
resourceFullType
});
});
WriteProperty(writer, "apiVersion", () => {
WriteProperty(writer, "enum", new string[] {
serviceClient.ApiVersion
});
});
WriteProperty(writer, "properties", () => {
WriteProperty(writer, "type", "object");
WriteProperty(writer, "properties", () => {
});
WriteProperty(writer, "required", new string[0]);
});
});
WriteProperty(writer, "required", new string[] {
"type",
"apiVersion",
"properties",
"location"
});
WriteProperty(writer, "description", resourceFullType);
});
}
});
});
}

await Write(stringWriter.ToString(), SchemaPath);
}

private static IEnumerable<Method> GetResourceMethods(ServiceClient serviceClient)
{
return GetResourceMethods(serviceClient.Methods);
}

private static IEnumerable<Method> GetResourceMethods(IEnumerable<Method> methods)
{
return methods.Where(m => m.Url.StartsWith(resourceMethodPrefix));
}

private static IEnumerable<string> GetResourceMethodUrisAfterPrefix(ServiceClient serviceClient)
{
IEnumerable<Method> resourceMethods = GetResourceMethods(serviceClient);
IEnumerable<string> resourceMethodUris = resourceMethods.Select(rm => rm.Url);
return resourceMethodUris.Select(rmu => rmu.Substring(resourceMethodPrefix.Length));
}

private static string GetResourceProvider(ServiceClient serviceClient)
{
IEnumerable<string> resourceMethodUrisAfterPrefix = GetResourceMethodUrisAfterPrefix(serviceClient);
return resourceMethodUrisAfterPrefix.Select(rmuap => rmuap.Substring(0, rmuap.IndexOf('/'))).Distinct().Single();
}

private static IEnumerable<string> GetResourceFullTypes(ServiceClient serviceClient)
{
IEnumerable<string> resourceMethodUrisAfterPrefix = GetResourceMethodUrisAfterPrefix(serviceClient);
return resourceMethodUrisAfterPrefix.Select(rmuap =>
{
int forwardSlashAfterProvider = rmuap.IndexOf('/');
int forwardSlashAfterType = rmuap.IndexOf('/', forwardSlashAfterProvider + 1);
int startIndex = forwardSlashAfterProvider + 1;
if (forwardSlashAfterType == -1)
{
return rmuap;
}
else
{
return rmuap.Substring(0, forwardSlashAfterType);
}
}).Distinct();
}

private static void WriteObject(JsonTextWriter writer, Action writeObjectContents)
{
writer.WriteStartObject();

writeObjectContents.Invoke();

writer.WriteEndObject();
}

private static void WriteProperty(JsonTextWriter writer, string propertyName, string propertyValue)
{
writer.WritePropertyName(propertyName);
writer.WriteValue(propertyValue);
}

private static void WriteProperty(JsonTextWriter writer, string propertyName, Action writeObjectContents)
{
writer.WritePropertyName(propertyName);
WriteObject(writer, writeObjectContents);
}

private static void WriteProperty(JsonTextWriter writer, string propertyName, string[] writeArrayContents)
{
writer.WritePropertyName(propertyName);
writer.WriteStartArray();

foreach (string value in writeArrayContents)
{
writer.WriteValue(value);
}

writer.WriteEndArray();
}
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
<?xml version="1.0" encoding="utf-8"?>
<packages>
<package id="Newtonsoft.Json" version="7.0.1" targetFramework="net45" />
</packages>

0 comments on commit ffb8fa3

Please sign in to comment.