Skip to content

Open api schema diff - #316

Merged
Shweta Patil (Shwetap05) merged 12 commits into
vnextfrom
OpenApiSchemaDiff
Oct 1, 2018
Merged

Open api schema diff#316
Shweta Patil (Shwetap05) merged 12 commits into
vnextfrom
OpenApiSchemaDiff

Conversation

@Shwetap05

Copy link
Copy Markdown
Member

Added more comparers.


using System.Collections.Generic;
using System.Linq;
using Microsoft.OpenApi.Models;

@Shwetap05 Shweta Patil (Shwetap05) Aug 16, 2018

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

ft.OpenAp [](start = 13, length = 9)

Still adding more tests for comparers #Closed

}

var comparisionContext = new ComparisonContext(new OpenApiComparerFactory());
var comparisionContext = new ComparisonContext(new OpenApiComparerFactory(), source, target);

@PerthCharern PerthCharern Sep 26, 2018

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

comparisionContext [](start = 16, length = 18)

nit, typo #Closed

/// <param name="source">The source.</param>
/// <param name="target">The target.</param>
/// <param name="comparisonContext">The context under which to compare the objects.</param>
internal void Compare<TE>(Enum source, Enum target, ComparisonContext comparisonContext)

@PerthCharern PerthCharern Sep 26, 2018

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

TE [](start = 30, length = 2)

TEnum #Closed


WalkAndCompare(
comparisonContext,
OpenApiConstants.Components,

@PerthCharern PerthCharern Sep 26, 2018

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Components [](start = 33, length = 10)

Servers #Closed

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

good catch :-)


In reply to: 220656072 [](ancestors = 220656072)

comparisonContext.AddOpenApiDifference(new OpenApiDifference
{
OpenApiDifferenceOperation = OpenApiDifferenceOperation.Update,
OpenApiComparedElementType = typeof(T),

@PerthCharern PerthCharern Sep 26, 2018

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

T [](start = 56, length = 1)

TEnum? #Closed

@PerthCharern

PerthCharern commented Sep 26, 2018

Copy link
Copy Markdown
Contributor
        comparisonContext.Enter(segment.Replace("/", "~1"));

need to escape ~ to ~0 too.

comparisonContext.Enter(segment.Replace("~", "~0").Replace("/", "~1"));

Same thing with the one below. #Closed


Refers to: src/Microsoft.OpenApi/Services/OpenApiComparerBase.cs:152 in 4a66112. [](commit_id = 4a66112, deletion_comment = False)

WalkAndCompare(comparisonContext, OpenApiConstants.AllowReserved,
() => Compare(sourceEncoding.AllowReserved, targetEncoding.AllowReserved, comparisonContext));


@PerthCharern PerthCharern Sep 26, 2018

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

nit, remove this extra line #Closed

@PerthCharern

PerthCharern commented Sep 26, 2018

Copy link
Copy Markdown
Contributor

}

Add comparer for reference object? #Closed


Refers to: src/Microsoft.OpenApi/Services/OpenApiParameterComparer.cs:61 in 4a66112. [](commit_id = 4a66112, deletion_comment = False)

{
WalkAndAddOpenApiDifference(
comparisonContext,
"$ref",

@PerthCharern PerthCharern Sep 26, 2018

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

"$ref" [](start = 20, length = 6)

Use DollarRef constant #Closed

if (sourceHeader.Reference != null)
{
sourceHeader = (OpenApiHeader) comparisonContext.SourceDocument.ResolveReference(
targetHeader.Reference);

@PerthCharern PerthCharern Sep 26, 2018

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

targetHeader [](start = 20, length = 12)

sourceHeader #Closed


WalkAndCompare(
comparisonContext,
OpenApiConstants.Content,

@PerthCharern PerthCharern Sep 26, 2018

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Content [](start = 33, length = 7)

Encoding #Closed

@PerthCharern

PerthCharern commented Sep 26, 2018

Copy link
Copy Markdown
Contributor
public static class OpenApiComparer

Is it not possible to model this based on the VisitorBase, i.e. in a similar way to https://github.com/Microsoft/OpenAPI.NET/blob/vnext/src/Microsoft.OpenApi/Validations/OpenApiValidator.cs? #Closed


Refers to: src/Microsoft.OpenApi/Services/OpenApiComparer.cs:12 in 4a66112. [](commit_id = 4a66112, deletion_comment = False)

{
WalkAndAddOpenApiDifference(
comparisonContext,
"$ref",

@PerthCharern PerthCharern Sep 26, 2018

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

"$ref" [](start = 20, length = 6)

DollarRef constant #Closed

{
WalkAndAddOpenApiDifference(
comparisonContext,
"$ref",

@PerthCharern PerthCharern Sep 26, 2018

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

"$ref" [](start = 20, length = 6)

DollarRef constant #Closed


WalkAndCompare(
comparisonContext,
OpenApiConstants.Components,

@PerthCharern PerthCharern Sep 26, 2018

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Components [](start = 33, length = 10)

Servers #Closed

@PerthCharern

PerthCharern commented Sep 26, 2018

Copy link
Copy Markdown
Contributor
                i.ToString(),

This number is misleading.

It's a bit difficult to show the differences of a list. Suppose

source = [1,2,3]
target = [3,1,4,5]

How do we want to report this?

The easiest way seems to be the most straightforward way: report as updates 1->3, 2->1, 3->4 (indexing is easy), and then add 5.

But if
source = [1,2,3]
target = [1,3,4]

It seems like the easiest way to understand this is to report that 2 has been removed and 4 has been added.

However, this is not easy to determined.

First, we need to get the sublist of the two (in this case [1,3]). If we see that everything in the sublist is still in the same order, then we can report the rest as simply additions or deletions.

I think it's fine if we want to add in this "smarter" method later and simply report it with a straightforward way in this PR (go element by element). In this case, we should report it as updates (2->3 and 3->4).

You can decide. #Closed


Refers to: src/Microsoft.OpenApi/Services/OpenApiParametersComparer.cs:46 in 4a66112. [](commit_id = 4a66112, deletion_comment = False)


WalkAndCompare(
comparisonContext,
OpenApiConstants.Parameters,

@PerthCharern PerthCharern Sep 26, 2018

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Parameters [](start = 33, length = 10)

Servers #Closed

@PerthCharern

PerthCharern commented Sep 26, 2018

Copy link
Copy Markdown
Contributor
public static class OpenApiComparer

That way, we don't need to handle the walking separately. We can use it as:

var comparingWalker = new OpenApiWalker(openApiComparer)

directly.

Something like how we use the validators in this test:

https://github.com/Microsoft/OpenAPI.NET/blob/vnext/test/Microsoft.OpenApi.Tests/Services/OpenApiValidatorTests.cs


In reply to: 424881544 [](ancestors = 424881544)


Refers to: src/Microsoft.OpenApi/Services/OpenApiComparer.cs:12 in 4a66112. [](commit_id = 4a66112, deletion_comment = False)

&& expectedDiff.OpenApiDifferenceOperation ==
actualDiff.OpenApiDifferenceOperation)).ToList();

notExpectedDifferences.Count.ShouldBeEquivalentTo(0);

@PerthCharern PerthCharern Sep 26, 2018

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Can't we just do

differences.ShouldBeEquivalentTo(expectedDifferences) ? #Closed

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Same comment with other test files.


In reply to: 220743939 [](ancestors = 220743939)

@Shwetap05 Shweta Patil (Shwetap05) Sep 27, 2018

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

So i can't do that, as in the difference result we have SourceValue and TargetValue of type object and equivalent fails when i use the actual type e.g. Server in expected result.

That is why only comparing fields except Target And Source


In reply to: 220743996 [](ancestors = 220743996,220743939)

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

ShouldBeEquivalentTo should be able to to do a deep comparison into any object type. In your expectedDifferences, you can assign the correct sourceValue and targetValue and FluentAssertion should be able to compare it with the differences you got.

In the case there's a bug in FluentAssertion library and the above doesn't work, you can simply exclude certain path from comparison in fluent assertion. https://stackoverflow.com/questions/22142576/how-to-use-exclude-in-fluentassertions-for-property-in-collection

This will ensure this test has good coverage even when we update OpenApiDifference in the future.


In reply to: 221082998 [](ancestors = 221082998,220743996,220743939)

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

interesting it worked, i remember it not working somewhere will fix all test.


In reply to: 221094506 [](ancestors = 221094506,221082998,220743996,220743939)

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It actually does compare, right? Did you try testing it by intentionally making it fail? Just want to make sure it's not just giving out an automatic pass without comparing.


In reply to: 221702898 [](ancestors = 221702898,221094506,221082998,220743996,220743939)

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

yes tested it, it does compare it and not false positive.


In reply to: 221749561 [](ancestors = 221749561,221702898,221094506,221082998,220743996,220743939)

@PerthCharern PerthCharern left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🕐

@PerthCharern PerthCharern added the type:feature New experience request label Sep 27, 2018
@Shwetap05

Shweta Patil (Shwetap05) commented Sep 27, 2018

Copy link
Copy Markdown
Member Author
                i.ToString(),

The diff that is being performed above is not index to index so if

source = [1,2,3]
target =[3,1,4,5]

diff is : New parameters 4,5 but the index of them in path would be 0.1 which is not correct, it should be 2,3 respectively.

Removed parameter 2, but the index of it in path would be 0, again not correct and should be 1.

so i will fix code to represent the location from the source/target list. so targetParameters.IndexOf( newParametersInTarget[i] ).ToString() for new parameters


In reply to: 424889731 [](ancestors = 424889731)


Refers to: src/Microsoft.OpenApi/Services/OpenApiParametersComparer.cs:46 in 4a66112. [](commit_id = 4a66112, deletion_comment = False)

@Shwetap05

Copy link
Copy Markdown
Member Author

}

added a to do for it. Will take care of it in next PR.


In reply to: 424879209 [](ancestors = 424879209)


Refers to: src/Microsoft.OpenApi/Services/OpenApiParameterComparer.cs:61 in 4a66112. [](commit_id = 4a66112, deletion_comment = False)

@Shwetap05

Shweta Patil (Shwetap05) commented Sep 27, 2018

Copy link
Copy Markdown
Member Author
public static class OpenApiComparer

While designing this feature i did go through these files implementing visitor pattern, and couldn't use them b/c VisitorBase is the class that manages path stack and Validator derives from it and leverages visiting logic from it. But Comparer cannot derive from VisitorBase as it just visits one document. Make sense?


In reply to: 424890444 [](ancestors = 424890444,424881544)


Refers to: src/Microsoft.OpenApi/Services/OpenApiComparer.cs:12 in 4a66112. [](commit_id = 4a66112, deletion_comment = False)

@PerthCharern

PerthCharern commented Sep 27, 2018

Copy link
Copy Markdown
Contributor
public static class OpenApiComparer

That's fair. There might be a way to unify these two, but that can be done as a separate work.


In reply to: 425254973 [](ancestors = 425254973,424890444,424881544)


Refers to: src/Microsoft.OpenApi/Services/OpenApiComparer.cs:12 in 4a66112. [](commit_id = 4a66112, deletion_comment = False)

@PerthCharern

Copy link
Copy Markdown
Contributor
                i.ToString(),

But order should matter.

If

source [3,1]
target [1,3]

This should report 2 updates. If we are not going with the index-to-index comparison, we'll need to first find a baseline on how to determine which objects remain the same in the list.


In reply to: 425251278 [](ancestors = 425251278,424889731)


Refers to: src/Microsoft.OpenApi/Services/OpenApiParametersComparer.cs:46 in 4a66112. [](commit_id = 4a66112, deletion_comment = False)

@PerthCharern

PerthCharern commented Sep 27, 2018

Copy link
Copy Markdown
Contributor
        comparisonContext.Enter(segment.Replace("/", "~1"));

It must be in the order I described above. Otherwise the ~ in ~1 will get replaced again.

i.e. / will be come ~01 (which is not what we want)


In reply to: 424875930 [](ancestors = 424875930)


Refers to: src/Microsoft.OpenApi/Services/OpenApiComparerBase.cs:152 in 4a66112. [](commit_id = 4a66112, deletion_comment = False)

@Shwetap05

Copy link
Copy Markdown
Member Author
                i.ToString(),

But if i am consumer of diff and i moved around my parameters in terms of index so per me that should generate a diff


In reply to: 425256973 [](ancestors = 425256973,425251278,424889731)


Refers to: src/Microsoft.OpenApi/Services/OpenApiParametersComparer.cs:46 in 4a66112. [](commit_id = 4a66112, deletion_comment = False)

@Shwetap05

Copy link
Copy Markdown
Member Author
        comparisonContext.Enter(segment.Replace("/", "~1"));

ah yes. long day for me :-).


In reply to: 425257539 [](ancestors = 425257539,424875930)


Refers to: src/Microsoft.OpenApi/Services/OpenApiComparerBase.cs:152 in 4a66112. [](commit_id = 4a66112, deletion_comment = False)

@PerthCharern

Copy link
Copy Markdown
Contributor
                i.ToString(),

Not sure if I understand. Based on the current code, if you put in something like

source [3,1]
target [1,3]

it will not generate any diff. This doesn't sound right to me.


In reply to: 425257623 [](ancestors = 425257623,425256973,425251278,424889731)


Refers to: src/Microsoft.OpenApi/Services/OpenApiParametersComparer.cs:46 in 4a66112. [](commit_id = 4a66112, deletion_comment = False)

@Shwetap05

Copy link
Copy Markdown
Member Author
                i.ToString(),

so if you perform suppose a string list compare options in C# it also does index variant compare and it will not result in diff. And if in a OpenApiDocument i have parameters shuffled around e.g. like below it should not result in diff

SOURCE
"parameters": [
{
"name": "sampleHeaderParam1",
"in": "header"
},
{
"name": "sampleHeaderParam2",
"in": "header"
}
}
}

TARGET:

"parameters": [
{
"name": "sampleHeaderParam2",
"in": "header"
},
{
"name": "sampleHeaderParam1",
"in": "header"
}
}
}


In reply to: 425258563 [](ancestors = 425258563,425257623,425256973,425251278,424889731)


Refers to: src/Microsoft.OpenApi/Services/OpenApiParametersComparer.cs:46 in 4a66112. [](commit_id = 4a66112, deletion_comment = False)

@PerthCharern

Copy link
Copy Markdown
Contributor
                i.ToString(),

Is that the behavior we want though?

  • From the spec point of view, It's kinda ambiguous whether an order matters in a list. But usually, a list is ordered. Otherwise, they should use the word set.

There's a bit of hint suggesting that order matters in the tags section of the OpenApi Object.

https://github.com/OAI/OpenAPI-Specification/blob/master/versions/3.0.0.md#openapi-object

  • From JSON/YAML point of view, they are 2 different JSON/YAMLs.

  • From a practical point of view, this definitely causes behavioral differences in terms of tooling. Swagger UI will order these 2 parameters differently.

I don't think they should be considered the same list.


In reply to: 425260367 [](ancestors = 425260367,425258563,425257623,425256973,425251278,424889731)


Refers to: src/Microsoft.OpenApi/Services/OpenApiParametersComparer.cs:46 in 4a66112. [](commit_id = 4a66112, deletion_comment = False)

@Shwetap05

Copy link
Copy Markdown
Member Author
                i.ToString(),

May be we can provide both options as setting so consumer of library can set it based on their needs, i will chat with you offline tomorrow about this in more details.


In reply to: 425262254 [](ancestors = 425262254,425260367,425258563,425257623,425256973,425251278,424889731)


Refers to: src/Microsoft.OpenApi/Services/OpenApiParametersComparer.cs:46 in 4a66112. [](commit_id = 4a66112, deletion_comment = False)

@PerthCharern

Copy link
Copy Markdown
Contributor
                i.ToString(),

Discussed with Shweta Patil (@Shwetap05). We will use sourceIndex for removal, and targetIndex for addition. We will treat parameter list as unordered given its semantic meaning.


In reply to: 425273672 [](ancestors = 425273672,425262254,425260367,425258563,425257623,425256973,425251278,424889731)


Refers to: src/Microsoft.OpenApi/Services/OpenApiParametersComparer.cs:46 in 4a66112. [](commit_id = 4a66112, deletion_comment = False)

@PerthCharern

PerthCharern commented Sep 28, 2018

Copy link
Copy Markdown
Contributor
        }

What if only one is null? #Closed


Refers to: src/Microsoft.OpenApi/Services/OpenApiParametersComparer.cs:31 in 91a905d. [](commit_id = 91a905d, deletion_comment = False)

@PerthCharern

PerthCharern commented Sep 28, 2018

Copy link
Copy Markdown
Contributor
        }

We should simply add one OpenApiDifference (add or remove) the parameters itself, not the item, is that right?


In reply to: 425517341 [](ancestors = 425517341)


Refers to: src/Microsoft.OpenApi/Services/OpenApiParametersComparer.cs:31 in 91a905d. [](commit_id = 91a905d, deletion_comment = False)

WalkAndAddOpenApiDifference(
comparisonContext,
i.ToString(),
targetParameters.IndexOf(newParametersInTarget[i]).ToString(),

@PerthCharern PerthCharern Sep 28, 2018

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

.IndexOf(newParametersInTarget[i]) [](start = 36, length = 34)

Interesting way to use IndexOf. :) #Closed

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

:-), i can use for each loop now


In reply to: 221335001 [](ancestors = 221335001)

@Shwetap05

Copy link
Copy Markdown
Member Author
        }

oh looks like i missed that, yes i think i should add one diff with parameters


In reply to: 425517623 [](ancestors = 425517623,425517341)


Refers to: src/Microsoft.OpenApi/Services/OpenApiParametersComparer.cs:31 in 91a905d. [](commit_id = 91a905d, deletion_comment = False)


WalkAndCompare(
comparisonContext,
i.ToString(),

@PerthCharern PerthCharern Sep 28, 2018

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

              i.ToString(), [](start = 1, length = 32)

This one is kinda tricky but I think it's already alright. It makes sense to use the source index here. #Closed

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Update: With the changes as discussed, we will need to use the target index here.


In reply to: 221344148 [](ancestors = 221344148)

@PerthCharern

PerthCharern commented Sep 28, 2018

Copy link
Copy Markdown
Contributor
        }

As discussed, switch these two loops and reverse the order in the source loop. This will make our difference list compliant to JSON PATCH. #Closed


Refers to: src/Microsoft.OpenApi/Services/OpenApiParametersComparer.cs:70 in 91a905d. [](commit_id = 91a905d, deletion_comment = False)

@PerthCharern

Copy link
Copy Markdown
Contributor
        }

Yup. Based on your other comparers, that would be an Update. Not add/remove. My bad.


In reply to: 425523780 [](ancestors = 425523780,425517623,425517341)


Refers to: src/Microsoft.OpenApi/Services/OpenApiParametersComparer.cs:31 in 91a905d. [](commit_id = 91a905d, deletion_comment = False)

@PerthCharern PerthCharern left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

:shipit:

@Shwetap05
Shweta Patil (Shwetap05) merged commit 0c86ee2 into vnext Oct 1, 2018
@darrelmiller
Darrel (darrelmiller) deleted the OpenApiSchemaDiff branch February 28, 2021 18:55
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

type:feature New experience request

2 participants