diff --git a/.config/dotnet-tools.json b/.config/dotnet-tools.json new file mode 100644 index 0000000..e6df774 --- /dev/null +++ b/.config/dotnet-tools.json @@ -0,0 +1,13 @@ +{ + "version": 1, + "isRoot": true, + "tools": { + "husky": { + "version": "0.7.1", + "commands": [ + "husky" + ], + "rollForward": false + } + } +} \ No newline at end of file diff --git a/.editorconfig b/.editorconfig new file mode 100644 index 0000000..29aa48d --- /dev/null +++ b/.editorconfig @@ -0,0 +1,130 @@ +root = true + +[*] +charset = utf-8 +indent_style = space +indent_size = 4 +insert_final_newline = true +trim_trailing_whitespace = true +tab_width = 4 + +[*.cs] +#### Styles de nommage #### + +# Rgles de nommage + +dotnet_naming_rule.interface_should_be_begins_with_i.severity = suggestion +dotnet_naming_rule.interface_should_be_begins_with_i.symbols = interface +dotnet_naming_rule.interface_should_be_begins_with_i.style = begins_with_i + +dotnet_naming_rule.types_should_be_pascal_case.severity = suggestion +dotnet_naming_rule.types_should_be_pascal_case.symbols = types +dotnet_naming_rule.types_should_be_pascal_case.style = pascal_case + +dotnet_naming_rule.non_field_members_should_be_pascal_case.severity = suggestion +dotnet_naming_rule.non_field_members_should_be_pascal_case.symbols = non_field_members +dotnet_naming_rule.non_field_members_should_be_pascal_case.style = pascal_case + +# Spcifications de symboles + +dotnet_naming_symbols.interface.applicable_kinds = interface +dotnet_naming_symbols.interface.applicable_accessibilities = public, internal, private, protected, protected_internal, private_protected +dotnet_naming_symbols.interface.required_modifiers = + +dotnet_naming_symbols.types.applicable_kinds = class, struct, interface, enum +dotnet_naming_symbols.types.applicable_accessibilities = public, internal, private, protected, protected_internal, private_protected +dotnet_naming_symbols.types.required_modifiers = + +dotnet_naming_symbols.non_field_members.applicable_kinds = property, event, method +dotnet_naming_symbols.non_field_members.applicable_accessibilities = public, internal, private, protected, protected_internal, private_protected +dotnet_naming_symbols.non_field_members.required_modifiers = + +# Styles de nommage + +dotnet_naming_style.begins_with_i.required_prefix = I +dotnet_naming_style.begins_with_i.required_suffix = +dotnet_naming_style.begins_with_i.word_separator = +dotnet_naming_style.begins_with_i.capitalization = pascal_case + +dotnet_naming_style.pascal_case.required_prefix = +dotnet_naming_style.pascal_case.required_suffix = +dotnet_naming_style.pascal_case.word_separator = +dotnet_naming_style.pascal_case.capitalization = pascal_case + +dotnet_naming_style.pascal_case.required_prefix = +dotnet_naming_style.pascal_case.required_suffix = +dotnet_naming_style.pascal_case.word_separator = +dotnet_naming_style.pascal_case.capitalization = pascal_case +csharp_style_expression_bodied_methods = false:silent +csharp_style_expression_bodied_constructors = false:silent +csharp_style_expression_bodied_operators = false:silent +csharp_style_expression_bodied_properties = true:silent +csharp_style_expression_bodied_indexers = true:silent +csharp_style_expression_bodied_accessors = true:silent +csharp_style_expression_bodied_lambdas = true:silent +csharp_style_expression_bodied_local_functions = false:silent +csharp_style_prefer_switch_expression = true:suggestion +csharp_style_prefer_pattern_matching = true:silent +csharp_style_pattern_matching_over_is_with_cast_check = true:suggestion +csharp_style_pattern_matching_over_as_with_null_check = true:suggestion +csharp_style_prefer_not_pattern = true:suggestion +csharp_style_prefer_extended_property_pattern = true:suggestion +csharp_prefer_simple_using_statement = true:suggestion +csharp_prefer_braces = true:silent +csharp_style_namespace_declarations = block_scoped:silent +csharp_style_prefer_method_group_conversion = true:silent +csharp_style_prefer_top_level_statements = true:silent +csharp_style_prefer_primary_constructors = true:suggestion + +[*.vb] +#### Styles de nommage #### + +# Rgles de nommage + +dotnet_naming_rule.interface_should_be_commence_par_i.severity = suggestion +dotnet_naming_rule.interface_should_be_commence_par_i.symbols = interface +dotnet_naming_rule.interface_should_be_commence_par_i.style = commence_par_i + +dotnet_naming_rule.types_should_be_casse_pascal.severity = suggestion +dotnet_naming_rule.types_should_be_casse_pascal.symbols = types +dotnet_naming_rule.types_should_be_casse_pascal.style = casse_pascal + +dotnet_naming_rule.membres_autres_que_des_champs_should_be_casse_pascal.severity = suggestion +dotnet_naming_rule.membres_autres_que_des_champs_should_be_casse_pascal.symbols = membres_autres_que_des_champs +dotnet_naming_rule.membres_autres_que_des_champs_should_be_casse_pascal.style = casse_pascal + +# Spcifications de symboles + +dotnet_naming_symbols.interface.applicable_kinds = interface +dotnet_naming_symbols.interface.applicable_accessibilities = public, friend, private, protected, protected_friend, private_protected +dotnet_naming_symbols.interface.required_modifiers = + +dotnet_naming_symbols.types.applicable_kinds = class, struct, interface, enum +dotnet_naming_symbols.types.applicable_accessibilities = public, friend, private, protected, protected_friend, private_protected +dotnet_naming_symbols.types.required_modifiers = + +dotnet_naming_symbols.membres_autres_que_des_champs.applicable_kinds = property, event, method +dotnet_naming_symbols.membres_autres_que_des_champs.applicable_accessibilities = public, friend, private, protected, protected_friend, private_protected +dotnet_naming_symbols.membres_autres_que_des_champs.required_modifiers = + +# Styles de nommage + +dotnet_naming_style.commence_par_i.required_prefix = I +dotnet_naming_style.commence_par_i.required_suffix = +dotnet_naming_style.commence_par_i.word_separator = +dotnet_naming_style.commence_par_i.capitalization = pascal_case + +dotnet_naming_style.casse_pascal.required_prefix = +dotnet_naming_style.casse_pascal.required_suffix = +dotnet_naming_style.casse_pascal.word_separator = +dotnet_naming_style.casse_pascal.capitalization = pascal_case + +dotnet_naming_style.casse_pascal.required_prefix = +dotnet_naming_style.casse_pascal.required_suffix = +dotnet_naming_style.casse_pascal.word_separator = +dotnet_naming_style.casse_pascal.capitalization = pascal_case + + +[*.{cs,vb}] +dotnet_diagnostic.IDE0073.severity = error +file_header_template = \nCopyright The Microcks Authors.\n\nLicensed under the Apache License, Version 2.0 (the "License")\nyou may not use this file except in compliance with the License.\nYou may obtain a copy of the License at\n\n http://www.apache.org/licenses/LICENSE-2.0 \n\nUnless required by applicable law or agreed to in writing, software\ndistributed under the License is distributed on an "AS IS" BASIS,\nWITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\nSee the License for the specific language governing permissions and\nlimitations under the License.\n\n diff --git a/.github/CODEOWNERS b/.github/CODEOWNERS new file mode 100644 index 0000000..62c6e61 --- /dev/null +++ b/.github/CODEOWNERS @@ -0,0 +1 @@ +* @SebastienDegodez \ No newline at end of file diff --git a/.github/dependabot.yml b/.github/dependabot.yml new file mode 100644 index 0000000..6ada163 --- /dev/null +++ b/.github/dependabot.yml @@ -0,0 +1,16 @@ +version: 2 +updates: + - package-ecosystem: "nuget" + directory: "/" + schedule: + interval: "weekly" + day: "sunday" + open-pull-requests-limit: 3 + rebase-strategy: disabled + - package-ecosystem: "github-actions" + directory: "/" + schedule: + interval: "weekly" + day: "sunday" + open-pull-requests-limit: 3 + rebase-strategy: disabled diff --git a/.github/pull-request-template.md b/.github/pull-request-template.md new file mode 100644 index 0000000..047da83 --- /dev/null +++ b/.github/pull-request-template.md @@ -0,0 +1,26 @@ +# Pull Request + + + +## Proposed Changes + + + +## Readiness Checklist + +### Author/Contributor + +- [ ] If documentation is needed for this change, has that been included in this pull request +- [ ] run `dotnet test` and ensure you have test coverage for the lines you are introducing +- [ ] run `dotnet husky run` and fix any issues that you have introduced + +### Reviewer + +- [ ] Label as either `feature`, `fix`, `documentation`, `enhancement`, `maintenance` or `breaking` diff --git a/.github/release-drafter.yml b/.github/release-drafter.yml new file mode 100644 index 0000000..b280d5c --- /dev/null +++ b/.github/release-drafter.yml @@ -0,0 +1,89 @@ +# Configuration for Release Drafter: https://github.com/toolmantim/release-drafter +name-template: "$RESOLVED_VERSION" +tag-template: "$RESOLVED_VERSION" +change-template: "- #$NUMBER $TITLE @$AUTHOR" +sort-direction: ascending +# +categories: + - title: "🚨 Breaking changes" + labels: + - "breaking-change" + - title: "✨ New features" + labels: + - "new-feature" + - title: "🐛 Bug fixes" + labels: + - "bugfix" + - title: "🚀 Enhancements" + labels: + - "enhancement" + - "refactor" + - "performance" + - title: "🧰 Maintenance" + labels: + - "maintenance" + - "ci" + - title: "📚 Documentation" + labels: + - "documentation" + - title: "⬆️ Dependency updates" + collapse-after: 5 + labels: + - "dependencies" +# +exclude-labels: + - "sync" +# +autolabeler: + - label: "automation" + title: + - "/^(build|ci|perf|refactor|test).*/i" + - label: "enhancement" + title: + - "/^(style).*/i" + - label: "documentation" + title: + - "/^(docs).*/i" + - label: "feature" + title: + - "/^(feat).*/i" + - label: "fix" + title: + - "/^(fix).*/i" + - label: "infrastructure" + title: + - "/^(infrastructure).*/i" + - label: "maintenance" + title: + - "/^(chore|maintenance).*/i" + - label: "revert" + title: + - "/^(revert).*/i" +# +version-resolver: + major: + labels: + - "major" + - "breaking-change" + minor: + labels: + - "minor" + - "new-feature" + patch: + labels: + - "bugfix" + - "chore" + - "ci" + - "dependencies" + - "documentation" + - "enhancement" + - "performance" + - "refactor" + default: patch +# +template: | + ## What's changed + + $CHANGES + + **Full Changelog**: https://github.com/$OWNER/$REPOSITORY/compare/$PREVIOUS_TAG...v$RESOLVED_VERSION \ No newline at end of file diff --git a/.github/workflows/cicd.yml b/.github/workflows/cicd.yml new file mode 100644 index 0000000..bce7cda --- /dev/null +++ b/.github/workflows/cicd.yml @@ -0,0 +1,80 @@ +name: 'Continuous Integration' + +on: + push: + branches: + - main + pull_request: + branches: + - main + +env: + DOTNET_CLI_TELEMETRY_OPTOUT: 1 + DOTNET_SKIP_FIRST_TIME_EXPERIENCE: 1 + DOTNET_NOLOGO: 1 + +jobs: + commitlint: + name: 📝 Commitlint + uses: ./.github/workflows/steps.commitlint.yml + secrets: inherit + + version: + name: Define Version + uses: ./.github/workflows/steps.dotnet-version.yml + with: + runs-on: ubuntu-latest + secrets: inherit + + build_test: + name: 🔨 Build and test + needs: + - commitlint + - version + uses: ./.github/workflows/steps.dotnet-build-test.yml + with: + runs-on: ubuntu-latest + version: ${{ needs.version.outputs.version }} + publish-package: true + use-sonarcloud: false + secrets: inherit + + publish_test: + name: 📊 Publish Test + permissions: + contents: read + actions: read + checks: write + needs: + - build_test + uses: ./.github/workflows/steps.publish-test-reporter.yml + with: + runs-on: ubuntu-latest + secrets: inherit + + nuget_publish: + name: 📦 NuGet Publish + needs: + - commitlint + - build_test + if: ${{ needs.build_test.outputs.publish-package != false && github.actor != 'dependabot[bot]' }} + uses: ./.github/workflows/steps.dotnet-nuget-publish.yml + secrets: inherit + + release_drafter: + name: 📖 Draft Release + permissions: + # write permission is required to create a github release + contents: write + # write permission is required for autolabeler + # otherwise, read permission is required at least + pull-requests: read + if: ${{ needs.build_test.outputs.publish-package != false && github.actor != 'dependabot[bot]' && !needs.version.outputs.preReleaseTag }} + needs: + - commitlint + - version + - nuget_publish + uses: ./.github/workflows/steps.github-release-draft.yml + with: + version: ${{ needs.version.outputs.version }} + secrets: inherit diff --git a/.github/workflows/steps.commitlint.yml b/.github/workflows/steps.commitlint.yml new file mode 100644 index 0000000..d7dd972 --- /dev/null +++ b/.github/workflows/steps.commitlint.yml @@ -0,0 +1,21 @@ +on: + workflow_call: + inputs: + runs-on: + required: false + type: string + default: 'ubuntu-latest' + +jobs: + commitlint: + name: Check Conventional Commits + runs-on: ${{ inputs.runs-on }} + steps: + - name: 🔄 Checkout + uses: actions/checkout@v4 + with: + lfs: true + fetch-depth: 0 + + - name: Conventional Commitlint + uses: opensource-nepal/commitlint@v1 \ No newline at end of file diff --git a/.github/workflows/steps.dotnet-build-test.yml b/.github/workflows/steps.dotnet-build-test.yml new file mode 100644 index 0000000..550d355 --- /dev/null +++ b/.github/workflows/steps.dotnet-build-test.yml @@ -0,0 +1,127 @@ +on: + workflow_call: + inputs: + runs-on: + required: false + type: string + default: 'ubuntu-latest' + use-sonarcloud: + required: false + type: boolean + default: false + version: + required: true + type: string + publish-package: + required: false + type: boolean + default: false + secrets: + SONAR_ORGANIZATION: + required: false + SONAR_PROJECT: + required: false + outputs: + publish-package: + description: 'Publish package is enabled ?' + value: ${{ jobs.build_test.outputs.publish-package }} +jobs: + build_test: + runs-on: ${{ inputs.runs-on }} + + outputs: + publish-package: ${{ inputs.publish-package }} + + steps: + - name: 🔄 Checkout + uses: actions/checkout@v4 + with: + lfs: true + fetch-depth: 0 + + - name: 🛠️ Setup .NET + uses: actions/setup-dotnet@v4 + with: + global-json-file: global.json + + - name: 🛠️ Setup JDK 17 + if: ${{ inputs.use-sonarcloud == true }} + uses: actions/setup-java@v4.5.0 + with: + java-version: 17 + distribution: 'zulu' + + - name: 🛠️ Install SonarCloud scanner + if: ${{ inputs.use-sonarcloud == true }} + run: dotnet tool install --global dotnet-sonarscanner + + - name: 🔧 Restore .NET Tools + run: dotnet tool restore + + - name: 🔧 Restore dependencies + run: dotnet restore + + - name: 🏗 Build + run: dotnet build --configuration Release --no-restore + + - name: 🔍 Start SonarQube Analysis + if: ${{ inputs.use-sonarcloud == true }} + env: + GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} + SONAR_TOKEN: ${{ secrets.SONAR_TOKEN }} + run: | + dotnet-sonarscanner begin ` + /k:"${{ secrets.SONAR_PROJECT }}" ` + /o:"${{ secrets.SONAR_ORGANIZATION }}" ` + /d:sonar.token="${{ secrets.SONAR_TOKEN }}" ` + /d:sonar.host.url="https://sonarcloud.io" ` + /d:sonar.cs.opencover.reportsPaths="**/*.opencover.xml" ` + /v:"${{ inputs.version }}" + shell: pwsh + + - name: 🧪 Test .NET + id: test + run: | + dotnet test --no-build ` + --configuration Release ` + --logger trx ` + --collect:"XPlat Code Coverage" ` + --results-directory testresults + shell: pwsh + + - name: Stop SonarQube Analysis + if: ${{ inputs.use-sonarcloud == true && (success() || steps.test.conclusion == 'failure') }} + id: sonar + env: + GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} + SONAR_TOKEN: ${{ secrets.SONAR_TOKEN }} + run: | + dotnet-sonarscanner end /d:sonar.token="${{ secrets.SONAR_TOKEN }}" + + - name: 📤 Upload Test And Coverage Results + uses: actions/upload-artifact@v4 + if: always() # run this step even if previous step failed + with: + name: ${{ inputs.runs-on }} + path: testresults + + - name: 📦 Nuget Pack + if: ${{ inputs.publish-package }} + run: | + dotnet pack ` + --include-source ` + --configuration Release ` + --no-build ` + --no-restore ` + --output ${{ github.workspace }}/nugets/ ` + -p:PackageVersion="${{ inputs.version }}" + shell: pwsh + + - name: 📤 Upload Nuget Package + uses: actions/upload-artifact@v4 + if: ${{ inputs.publish-package }} + with: + if-no-files-found: error + name: nugets_${{ inputs.runs-on }} + path: nugets + diff --git a/.github/workflows/steps.dotnet-nuget-publish.yml b/.github/workflows/steps.dotnet-nuget-publish.yml new file mode 100644 index 0000000..912fe3d --- /dev/null +++ b/.github/workflows/steps.dotnet-nuget-publish.yml @@ -0,0 +1,27 @@ +on: + workflow_call: + inputs: + runs-on: + required: false + type: string + default: 'ubuntu-latest' + secrets: + NUGET_KEY: + required: true +jobs: + nuget-publish: + if: ${{ github.event_name != 'pull_request' && github.ref == 'refs/heads/main' && github.repository == 'microcks/microcks-testcontainers-dotnet' }} + runs-on: ${{ inputs.runs-on }} + steps: + - name: 📥 Download artifact + uses: actions/download-artifact@v4 + with: + name: nugets_${{ inputs.runs-on }} + path: nuget_packages + + - name: 🚀 Publish Package to NuGet + run: dotnet nuget push nuget_packages/**/*.nupkg ` + -k ${{ secrets.NUGET_KEY }} ` + --skip-duplicate -n ` + -s https://api.nuget.org/v3/index.json + shell: pwsh diff --git a/.github/workflows/steps.dotnet-version.yml b/.github/workflows/steps.dotnet-version.yml new file mode 100644 index 0000000..798b4ae --- /dev/null +++ b/.github/workflows/steps.dotnet-version.yml @@ -0,0 +1,57 @@ +on: + workflow_call: + inputs: + runs-on: + required: false + type: string + default: 'ubuntu-latest' + outputs: + version: + description: 'The version based on git history (gitversion)' + value: ${{ jobs.define_version.outputs.version }} + preReleaseTag: + description: 'preReleaseTag (gitversion)' + value: ${{ jobs.define_version.outputs.preReleaseTag }} + majorMinorPatch: + description: 'majorMinorPatch (gitversion)' + value: ${{ jobs.define_version.outputs.majorMinorPatch }} +jobs: + define_version: + runs-on: ${{ inputs.runs-on }} + + outputs: + version: ${{ steps.gitversion.outputs.fullSemVer }} + preReleaseTag: ${{ steps.gitversion.outputs.preReleaseTag }} + majorMinorPatch: ${{ steps.gitversion.outputs.majorMinorPatch }} + + steps: + - name: 🔄 Checkout + uses: actions/checkout@v4 + with: + lfs: true + fetch-depth: 0 + + - name: Read version from Directory.Build + id: gitversion + if: github.ref == 'refs/heads/main' + run: | + [xml]$xml = Get-Content -Path .\Directory.Build.props + $majorMinorPatch = ([string]$xml.Project.PropertyGroup.VersionPrefix).Trim() + + if (-not [string]::IsNullOrEmpty($majorMinorPatch)) { $majorMinorPatch = $majorMinorPatch.Trim() } + echo "majorMinorPatch=$majorMinorPatch" >> $env:GITHUB_OUTPUT + + $preReleaseTag = ([string]$xml.Project.PropertyGroup.VersionSuffix).Trim() + if (-not [string]::IsNullOrEmpty($preReleaseTag)) { $preReleaseTag = $preReleaseTag.Trim() } + echo "preReleaseTag=$preReleaseTag" >> $env:GITHUB_OUTPUT + + $fullSemVer = $majorMinorPatch + if ([string]::IsNullOrEmpty($preReleaseTag) -eq $false) { $fullSemVer = "$majorMinorPatch-$preReleaseTag.$env:GITHUB_RUN_NUMBER" } + echo "fullSemVer=$fullSemVer" >> $env:GITHUB_OUTPUT + shell: pwsh + + - name: Display GitVersion outputs + run: | + echo "Version: ${{ steps.gitversion.outputs.fullSemVer }}" + echo "MajorMinorPatch: ${{ steps.gitversion.outputs.majorMinorPatch }}" + echo "PreReleaseTag: ${{ steps.gitversion.outputs.preReleaseTag }}" \ No newline at end of file diff --git a/.github/workflows/steps.github-release-draft.yml b/.github/workflows/steps.github-release-draft.yml new file mode 100644 index 0000000..79df02f --- /dev/null +++ b/.github/workflows/steps.github-release-draft.yml @@ -0,0 +1,29 @@ +on: + workflow_call: + inputs: + runs-on: + required: false + type: string + default: ubuntu-latest + version: + required: true + type: string + +jobs: + release_drafter: + if: ${{ github.event_name != 'pull_request' && github.ref == 'refs/heads/main' }} + runs-on: ${{ inputs.runs-on }} + steps: + - name: 🔄 Checkout + uses: actions/checkout@v4 + with: + lfs: true + fetch-depth: 0 + + - name: Release Drafter + uses: release-drafter/release-drafter@v6.0.0 + with: + version: ${{ inputs.version }} + publish: true + env: + GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} diff --git a/.github/workflows/steps.publish-test-reporter.yml b/.github/workflows/steps.publish-test-reporter.yml new file mode 100644 index 0000000..76802b9 --- /dev/null +++ b/.github/workflows/steps.publish-test-reporter.yml @@ -0,0 +1,20 @@ +on: + workflow_call: + inputs: + runs-on: + required: false + type: string + default: 'ubuntu-latest' + +jobs: + report: + runs-on: ${{ inputs.runs-on }} + + steps: + - name: 📊 Publish Test Report + uses: dorny/test-reporter@v1.9.1 + with: + artifact: ${{ inputs.runs-on }} + name: report (${{ inputs.runs-on }}) + path: '*.trx' + reporter: dotnet-trx \ No newline at end of file diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..60b2ea0 --- /dev/null +++ b/.gitignore @@ -0,0 +1,400 @@ +## Ignore Visual Studio temporary files, build results, and +## files generated by popular Visual Studio add-ons. +## +## Get latest from https://github.com/github/gitignore/blob/main/VisualStudio.gitignore + +# User-specific files +*.rsuser +*.suo +*.user +*.userosscache +*.sln.docstates + +# User-specific files (MonoDevelop/Xamarin Studio) +*.userprefs + +# Mono auto generated files +mono_crash.* + +# Build results +[Dd]ebug/ +[Dd]ebugPublic/ +[Rr]elease/ +[Rr]eleases/ +x64/ +x86/ +[Ww][Ii][Nn]32/ +[Aa][Rr][Mm]/ +[Aa][Rr][Mm]64/ +bld/ +[Bb]in/ +[Oo]bj/ +[Ll]og/ +[Ll]ogs/ + +# Visual Studio 2015/2017 cache/options directory +.vs/ +# Uncomment if you have tasks that create the project's static files in wwwroot +#wwwroot/ + +# Visual Studio 2017 auto generated files +Generated\ Files/ + +# MSTest test Results +[Tt]est[Rr]esult*/ +[Bb]uild[Ll]og.* + +# NUnit +*.VisualState.xml +TestResult.xml +nunit-*.xml + +# Build Results of an ATL Project +[Dd]ebugPS/ +[Rr]eleasePS/ +dlldata.c + +# Benchmark Results +BenchmarkDotNet.Artifacts/ + +# .NET Core +project.lock.json +project.fragment.lock.json +artifacts/ + +# ASP.NET Scaffolding +ScaffoldingReadMe.txt + +# StyleCop +StyleCopReport.xml + +# Files built by Visual Studio +*_i.c +*_p.c +*_h.h +*.ilk +*.meta +*.obj +*.iobj +*.pch +*.pdb +*.ipdb +*.pgc +*.pgd +*.rsp +# but not Directory.Build.rsp, as it configures directory-level build defaults +!Directory.Build.rsp +*.sbr +*.tlb +*.tli +*.tlh +*.tmp +*.tmp_proj +*_wpftmp.csproj +*.log +*.tlog +*.vspscc +*.vssscc +.builds +*.pidb +*.svclog +*.scc + +# Chutzpah Test files +_Chutzpah* + +# Visual C++ cache files +ipch/ +*.aps +*.ncb +*.opendb +*.opensdf +*.sdf +*.cachefile +*.VC.db +*.VC.VC.opendb + +# Visual Studio profiler +*.psess +*.vsp +*.vspx +*.sap + +# Visual Studio Trace Files +*.e2e + +# TFS 2012 Local Workspace +$tf/ + +# Guidance Automation Toolkit +*.gpState + +# ReSharper is a .NET coding add-in +_ReSharper*/ +*.[Rr]e[Ss]harper +*.DotSettings.user + +# TeamCity is a build add-in +_TeamCity* + +# DotCover is a Code Coverage Tool +*.dotCover + +# AxoCover is a Code Coverage Tool +.axoCover/* +!.axoCover/settings.json + +# Coverlet is a free, cross platform Code Coverage Tool +coverage*.json +coverage*.xml +coverage*.info + +# Visual Studio code coverage results +*.coverage +*.coveragexml + +# NCrunch +_NCrunch_* +.*crunch*.local.xml +nCrunchTemp_* + +# MightyMoose +*.mm.* +AutoTest.Net/ + +# Web workbench (sass) +.sass-cache/ + +# Installshield output folder +[Ee]xpress/ + +# DocProject is a documentation generator add-in +DocProject/buildhelp/ +DocProject/Help/*.HxT +DocProject/Help/*.HxC +DocProject/Help/*.hhc +DocProject/Help/*.hhk +DocProject/Help/*.hhp +DocProject/Help/Html2 +DocProject/Help/html + +# Click-Once directory +publish/ + +# Publish Web Output +*.[Pp]ublish.xml +*.azurePubxml +# Note: Comment the next line if you want to checkin your web deploy settings, +# but database connection strings (with potential passwords) will be unencrypted +*.pubxml +*.publishproj + +# Microsoft Azure Web App publish settings. Comment the next line if you want to +# checkin your Azure Web App publish settings, but sensitive information contained +# in these scripts will be unencrypted +PublishScripts/ + +# NuGet Packages +*.nupkg +# NuGet Symbol Packages +*.snupkg +# The packages folder can be ignored because of Package Restore +**/[Pp]ackages/* +# except build/, which is used as an MSBuild target. +!**/[Pp]ackages/build/ +# Uncomment if necessary however generally it will be regenerated when needed +#!**/[Pp]ackages/repositories.config +# NuGet v3's project.json files produces more ignorable files +*.nuget.props +*.nuget.targets + +# Microsoft Azure Build Output +csx/ +*.build.csdef + +# Microsoft Azure Emulator +ecf/ +rcf/ + +# Windows Store app package directories and files +AppPackages/ +BundleArtifacts/ +Package.StoreAssociation.xml +_pkginfo.txt +*.appx +*.appxbundle +*.appxupload + +# Visual Studio cache files +# files ending in .cache can be ignored +*.[Cc]ache +# but keep track of directories ending in .cache +!?*.[Cc]ache/ + +# Others +ClientBin/ +~$* +*~ +*.dbmdl +*.dbproj.schemaview +*.jfm +*.pfx +*.publishsettings +orleans.codegen.cs + +# Including strong name files can present a security risk +# (https://github.com/github/gitignore/pull/2483#issue-259490424) +#*.snk + +# Since there are multiple workflows, uncomment next line to ignore bower_components +# (https://github.com/github/gitignore/pull/1529#issuecomment-104372622) +#bower_components/ + +# RIA/Silverlight projects +Generated_Code/ + +# Backup & report files from converting an old project file +# to a newer Visual Studio version. Backup files are not needed, +# because we have git ;-) +_UpgradeReport_Files/ +Backup*/ +UpgradeLog*.XML +UpgradeLog*.htm +ServiceFabricBackup/ +*.rptproj.bak + +# SQL Server files +*.mdf +*.ldf +*.ndf + +# Business Intelligence projects +*.rdl.data +*.bim.layout +*.bim_*.settings +*.rptproj.rsuser +*- [Bb]ackup.rdl +*- [Bb]ackup ([0-9]).rdl +*- [Bb]ackup ([0-9][0-9]).rdl + +# Microsoft Fakes +FakesAssemblies/ + +# GhostDoc plugin setting file +*.GhostDoc.xml + +# Node.js Tools for Visual Studio +.ntvs_analysis.dat +node_modules/ + +# Visual Studio 6 build log +*.plg + +# Visual Studio 6 workspace options file +*.opt + +# Visual Studio 6 auto-generated workspace file (contains which files were open etc.) +*.vbw + +# Visual Studio 6 auto-generated project file (contains which files were open etc.) +*.vbp + +# Visual Studio 6 workspace and project file (working project files containing files to include in project) +*.dsw +*.dsp + +# Visual Studio 6 technical files +*.ncb +*.aps + +# Visual Studio LightSwitch build output +**/*.HTMLClient/GeneratedArtifacts +**/*.DesktopClient/GeneratedArtifacts +**/*.DesktopClient/ModelManifest.xml +**/*.Server/GeneratedArtifacts +**/*.Server/ModelManifest.xml +_Pvt_Extensions + +# Paket dependency manager +.paket/paket.exe +paket-files/ + +# FAKE - F# Make +.fake/ + +# CodeRush personal settings +.cr/personal + +# Python Tools for Visual Studio (PTVS) +__pycache__/ +*.pyc + +# Cake - Uncomment if you are using it +# tools/** +# !tools/packages.config + +# Tabs Studio +*.tss + +# Telerik's JustMock configuration file +*.jmconfig + +# BizTalk build output +*.btp.cs +*.btm.cs +*.odx.cs +*.xsd.cs + +# OpenCover UI analysis results +OpenCover/ + +# Azure Stream Analytics local run output +ASALocalRun/ + +# MSBuild Binary and Structured Log +*.binlog + +# NVidia Nsight GPU debugger configuration file +*.nvuser + +# MFractors (Xamarin productivity tool) working folder +.mfractor/ + +# Local History for Visual Studio +.localhistory/ + +# Visual Studio History (VSHistory) files +.vshistory/ + +# BeatPulse healthcheck temp database +healthchecksdb + +# Backup folder for Package Reference Convert tool in Visual Studio 2017 +MigrationBackup/ + +# Ionide (cross platform F# VS Code tools) working folder +.ionide/ + +# Fody - auto-generated XML schema +FodyWeavers.xsd + +# VS Code files for those working on multiple tools +.vscode/* +!.vscode/settings.json +!.vscode/tasks.json +!.vscode/launch.json +!.vscode/extensions.json +*.code-workspace + +# Local History for Visual Studio Code +.history/ + +# Windows Installer files from build outputs +*.cab +*.msi +*.msix +*.msm +*.msp + +# JetBrains Rider +*.sln.iml \ No newline at end of file diff --git a/.husky/commit-msg b/.husky/commit-msg new file mode 100644 index 0000000..744cb60 --- /dev/null +++ b/.husky/commit-msg @@ -0,0 +1,4 @@ +#!/bin/sh +. "$(dirname "$0")/_/husky.sh" + +dotnet husky run --name commit-message-linter --args "$1" \ No newline at end of file diff --git a/.husky/task-runner.json b/.husky/task-runner.json new file mode 100644 index 0000000..9978230 --- /dev/null +++ b/.husky/task-runner.json @@ -0,0 +1,10 @@ +{ + "$schema": "https://alirezanet.github.io/Husky.Net/schema.json", + "tasks": [ + { + "name": "commit-message-linter", + "command": "dotnet", + "args": ["husky", "exec", ".husky/csx/commit-lint.csx", "--args" , "${args}"] + } + ] +} diff --git a/Directory.Build.props b/Directory.Build.props new file mode 100644 index 0000000..8939806 --- /dev/null +++ b/Directory.Build.props @@ -0,0 +1,23 @@ + + + + $(AssemblyName) + 0.1.0 + alpha + + Microcks.Testcontainers for .NET + Sébastien DEGODEZ + https://microcks.io/images/logo/microcks-logo-blue-stack_hub6b138b944a2655a28b25da35122648c_37956_417x415_resize_q90_h2_lanczos_3.webp + README.md + docker;dotnet;testcontainers;testing;microcks + git + https://github.com/microcks/microcks-testcontainers-dotnet + + + true + + + + + + diff --git a/README.md b/README.md index 0214d46..4fdd461 100644 --- a/README.md +++ b/README.md @@ -1,2 +1,101 @@ # microcks-testcontainers-dotnet .NET lib for Testcontainers that enables embedding Microcks into your unit tests with lightweight, throwaway instance thanks to containers. + + +## How to use it? + +### Include it into your project dependencies + +``` +dotnet add package Microcks.Testcontainers --version 0.1.0 +``` + +### Startup the container + +You just have to specify the container image you'd like to use. This library requires a Microcks `uber` distribution (with no MongoDB dependency). + + +```csharp +MicrocksContainer container = new MicrocksBuilder() + .WithImage("quay.io/microcks/microcks-uber:1.10.0") + .Build(); +await container.StartAsync(); +``` + +### Import content in Microcks + +To use Microcks mocks or contract-testing features, you first need to import OpenAPI, Postman Collection, GraphQL or gRPC artifacts. +Artifacts can be imported as main/Primary ones or as secondary ones. See [Multi-artifacts support](https://microcks.io/documentation/using/importers/#multi-artifacts-support) for details. + +You can do it before starting the container using simple paths: + +```csharp +MicrocksContainer container = new MicrocksBuilder() + .WithMainArtifacts("apipastries-openapi.yaml") + .WithSecondaryArtifacts("apipastries-postman-collection.json") + .Build(); +await container.StartAsync(); +``` + +or once the container started using `File` arguments: + +```csharp +container.ImportAsMainArtifact("apipastries-openapi.yaml"); +container.ImportAsSecondaryArtifact("apipastries-postman-collection.json"); +``` + +You can also import full [repository snapshots](https://microcks.io/documentation/administrating/snapshots/) at once: + +```csharp +MicrocksContainer container = new MicrocksBuilder() + .WithSnapshots("microcks-repository.json") + .Build(); +await container.StartAsync(); +``` + +### Using mock endpoints for your dependencies + +During your test setup, you'd probably need to retrieve mock endpoints provided by Microcks containers to +setup your base API url calls. You can do it like this: + +```csharp +var baseApiUrl = container.GetRestMockEndpoint("API Pastries", "0.0.1"); +``` + +The container provides methods for different supported API styles/protocols (Soap, GraphQL, gRPC,...). + +The container also provides `GetHttpEndpoint()` for raw access to those API endpoints. + +### Launching new contract-tests + +If you want to ensure that your application under test is conformant to an OpenAPI contract (or other type of contract), +you can launch a Microcks contract/conformance test using the local server port you're actually running. + +```csharp +private int port; + +public async Task InitializeAsync() +{ + container = new MicrocksBuilder() + .WithExposedPort(port) + .Build(); + await container.StartAsync(); +} + +[Fact] +public async Task testOpenAPIContract() +{ + var testRequest = new TestRequest + { + ServiceId = "API Pastries:0.0.1", + RunnerType = TestRunnerType.OPEN_API_SCHEMA, + TestEndpoint = $"http://host.testcontainers.internal:{port}", + Timeout = TimeSpan.FromMilliseconds(2000) + }; + TestResult testResult = await container.TestEndpointAsync(testRequest); + + testResult.Success.Should().BeTrue(); +} +``` + +The `TestResult` gives you access to all details regarding success of failure on different test cases. diff --git a/global.json b/global.json new file mode 100644 index 0000000..39c53b8 --- /dev/null +++ b/global.json @@ -0,0 +1,6 @@ +{ + "sdk": { + "version": "8.0.200", + "rollForward": "latestMinor" + } +} diff --git a/microcks-testcontainers-dotnet.sln b/microcks-testcontainers-dotnet.sln new file mode 100644 index 0000000..63a6fac --- /dev/null +++ b/microcks-testcontainers-dotnet.sln @@ -0,0 +1,45 @@ + +Microsoft Visual Studio Solution File, Format Version 12.00 +# Visual Studio Version 17 +VisualStudioVersion = 17.0.31903.59 +MinimumVisualStudioVersion = 10.0.40219.1 +Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Solution Items", "Solution Items", "{2A03BEC9-C788-45EC-AA51-341268BAC375}" + ProjectSection(SolutionItems) = preProject + .editorconfig = .editorconfig + global.json = global.json + EndProjectSection +EndProject +Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "src", "src", "{6B414F17-C857-4B37-B48F-4913F7E083CD}" +EndProject +Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "tests", "tests", "{85478875-E950-4D1A-B1DA-0FDC96B9586C}" +EndProject +Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Microcks.Testcontainers.Tests", "tests\Microcks.Testcontainers.Tests\Microcks.Testcontainers.Tests.csproj", "{9FC22581-0B9C-4B25-B10B-BCAF4A41497F}" +EndProject +Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Microcks.Testcontainers", "src\Microcks.Testcontainers\Microcks.Testcontainers.csproj", "{AD1DD5BB-8F23-4529-94D6-6F2963A094FD}" +EndProject +Global + GlobalSection(SolutionConfigurationPlatforms) = preSolution + Debug|Any CPU = Debug|Any CPU + Release|Any CPU = Release|Any CPU + EndGlobalSection + GlobalSection(ProjectConfigurationPlatforms) = postSolution + {9FC22581-0B9C-4B25-B10B-BCAF4A41497F}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {9FC22581-0B9C-4B25-B10B-BCAF4A41497F}.Debug|Any CPU.Build.0 = Debug|Any CPU + {9FC22581-0B9C-4B25-B10B-BCAF4A41497F}.Release|Any CPU.ActiveCfg = Release|Any CPU + {9FC22581-0B9C-4B25-B10B-BCAF4A41497F}.Release|Any CPU.Build.0 = Release|Any CPU + {AD1DD5BB-8F23-4529-94D6-6F2963A094FD}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {AD1DD5BB-8F23-4529-94D6-6F2963A094FD}.Debug|Any CPU.Build.0 = Debug|Any CPU + {AD1DD5BB-8F23-4529-94D6-6F2963A094FD}.Release|Any CPU.ActiveCfg = Release|Any CPU + {AD1DD5BB-8F23-4529-94D6-6F2963A094FD}.Release|Any CPU.Build.0 = Release|Any CPU + EndGlobalSection + GlobalSection(SolutionProperties) = preSolution + HideSolutionNode = FALSE + EndGlobalSection + GlobalSection(NestedProjects) = preSolution + {9FC22581-0B9C-4B25-B10B-BCAF4A41497F} = {85478875-E950-4D1A-B1DA-0FDC96B9586C} + {AD1DD5BB-8F23-4529-94D6-6F2963A094FD} = {6B414F17-C857-4B37-B48F-4913F7E083CD} + EndGlobalSection + GlobalSection(ExtensibilityGlobals) = postSolution + SolutionGuid = {885DCD4E-3AD1-41B2-BD3D-9E654F205C39} + EndGlobalSection +EndGlobal diff --git a/src/Microcks.Testcontainers/Converter/ArrayToStringDeserializer.cs b/src/Microcks.Testcontainers/Converter/ArrayToStringDeserializer.cs new file mode 100644 index 0000000..6c99463 --- /dev/null +++ b/src/Microcks.Testcontainers/Converter/ArrayToStringDeserializer.cs @@ -0,0 +1,52 @@ +// +// Copyright The Microcks Authors. +// +// 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. +// +// + +using System.Text.Json; +using System.Text.Json.Serialization; + +namespace Microcks.Testcontainers.Converter; + +/// +/// This class is used to convert an array of strings to a single string. +/// +public class ArrayToStringConverter : JsonConverter +{ + /// + public override string Read(ref Utf8JsonReader reader, Type typeToConvert, JsonSerializerOptions options) + { + if (reader.TokenType == JsonTokenType.StartArray) + { + var values = new List(); + while (reader.Read()) + { + if (reader.TokenType == JsonTokenType.EndArray) + { + break; + } + values.Add(reader.GetString()); + } + return string.Join(",", values); + } + return reader.GetString(); + } + + /// + public override void Write(Utf8JsonWriter writer, string value, JsonSerializerOptions options) + { + writer.WriteStringValue(value); + } +} diff --git a/src/Microcks.Testcontainers/Converter/TimeSpanToMillisecondsConverter.cs b/src/Microcks.Testcontainers/Converter/TimeSpanToMillisecondsConverter.cs new file mode 100644 index 0000000..8f73c2d --- /dev/null +++ b/src/Microcks.Testcontainers/Converter/TimeSpanToMillisecondsConverter.cs @@ -0,0 +1,39 @@ +// +// Copyright The Microcks Authors. +// +// 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. +// +// + +using System.Text.Json; +using System.Text.Json.Serialization; + +namespace Microcks.Testcontainers.Converter; + +/// +/// This class implements a custom JSON converter for to milliseconds. +/// +public class TimeSpanToMillisecondsConverter : JsonConverter +{ + /// + public override TimeSpan Read(ref Utf8JsonReader reader, Type typeToConvert, JsonSerializerOptions options) + { + return TimeSpan.FromMilliseconds(reader.GetInt64()); + } + + /// + public override void Write(Utf8JsonWriter writer, TimeSpan value, JsonSerializerOptions options) + { + writer.WriteNumberValue(value.TotalMilliseconds); + } +} diff --git a/src/Microcks.Testcontainers/Microcks.Testcontainers.csproj b/src/Microcks.Testcontainers/Microcks.Testcontainers.csproj new file mode 100644 index 0000000..afebd5a --- /dev/null +++ b/src/Microcks.Testcontainers/Microcks.Testcontainers.csproj @@ -0,0 +1,9 @@ + + + net6.0;net8.0;netstandard2.0;netstandard2.1 + latest + + + + + \ No newline at end of file diff --git a/src/Microcks.Testcontainers/MicrocksBuilder.cs b/src/Microcks.Testcontainers/MicrocksBuilder.cs new file mode 100644 index 0000000..e996690 --- /dev/null +++ b/src/Microcks.Testcontainers/MicrocksBuilder.cs @@ -0,0 +1,225 @@ +// +// Copyright The Microcks Authors. +// +// 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. +// +// + +namespace Microcks.Testcontainers; + +/// +public sealed class MicrocksBuilder : ContainerBuilder +{ + /// + /// Image name for the Microcks container. + /// + public const string MicrocksImage = "quay.io/microcks/microcks-uber"; + + /// + /// HTTP port for the Microcks container. + /// + public const ushort MicrocksHttpPort = 8080; + + /// + /// GRPC port for the Microcks container. + /// + public const ushort MicrocksGrpcPort = 9090; + + private List _snapshots; + + private List _mainRemoteArtifacts; + private List _mainArtifacts; + private List _secondaryArtifacts; + + private List _secrets; + + /// + /// Initializes a new instance of the class. + /// + public MicrocksBuilder() + : this(new MicrocksConfiguration()) + { + DockerResourceConfiguration = Init().DockerResourceConfiguration; + } + + /// + /// Initializes a new instance of the class. + /// + /// The Docker resource configuration. + private MicrocksBuilder(MicrocksConfiguration resourceConfiguration) + : base(resourceConfiguration) + { + DockerResourceConfiguration = resourceConfiguration; + } + + /// + protected override MicrocksConfiguration DockerResourceConfiguration { get; } + + /// + public override MicrocksContainer Build() + { + Validate(); + var container = new MicrocksContainer(DockerResourceConfiguration); + + container.Started += (_, _) => ContainerStarted(container); + + return container; + } + + private void ContainerStarted(MicrocksContainer container) + { + if (_snapshots != null && _snapshots.Any()) + { + _snapshots.ForEach(snapshot => container.ImportSnapshotAsync(snapshot).GetAwaiter().GetResult()); + } + + if (_mainRemoteArtifacts != null && _mainRemoteArtifacts.Any()) + { + _mainRemoteArtifacts.ForEach(remoteArtifactUrl => container.DownloadArtifactAsync(remoteArtifactUrl, main: true).GetAwaiter().GetResult()); + } + + if (_mainArtifacts != null && _mainArtifacts.Any()) + { + _mainArtifacts.ForEach(container.ImportAsMainArtifact); + } + + if (_secondaryArtifacts != null && _secondaryArtifacts.Any()) + { + _secondaryArtifacts.ForEach(container.ImportAsSecondaryArtifact); + } + + if (_secrets != null && _secrets.Any()) + { + _secrets.ForEach(secret => container.CreateSecretAsync(secret).GetAwaiter().GetResult()); + } + } + + + /// + protected override MicrocksBuilder Init() + { + return base.Init() + .WithImage(MicrocksImage) + .WithPortBinding(MicrocksHttpPort, true) + .WithPortBinding(MicrocksGrpcPort, true) + .WithWaitStrategy(Wait.ForUnixContainer().UntilMessageIsLogged(".*Started MicrocksApplication.*")); + } + + /// + protected override MicrocksBuilder Clone(IResourceConfiguration resourceConfiguration) + { + return Merge(DockerResourceConfiguration, new MicrocksConfiguration(resourceConfiguration)); + } + + /// + protected override MicrocksBuilder Clone(IContainerConfiguration resourceConfiguration) + { + return Merge(DockerResourceConfiguration, new MicrocksConfiguration(resourceConfiguration)); + } + + /// + protected override MicrocksBuilder Merge(MicrocksConfiguration oldValue, MicrocksConfiguration newValue) + { + return new MicrocksBuilder(new MicrocksConfiguration(oldValue, newValue)); + } + + /// + /// Set the snapshots to import into the Microcks container. + /// + /// + /// + public MicrocksBuilder WithSnapshots(params string[] snapshots) + { + if (_snapshots == null) + { + _snapshots = new List(snapshots); + } + else + { + _snapshots.AddRange(snapshots); + } + return this; + } + + /// + /// Set the main remote artifacts to download into the Microcks container. + /// + /// + /// + public MicrocksBuilder WithMainRemoteArtifacts(params string[] urls) + { + if (_mainRemoteArtifacts == null) + { + _mainRemoteArtifacts = new List(urls); + } + else + { + _mainRemoteArtifacts.AddRange(urls); + } + return this; + } + + /// + /// Set the main artifacts to import into the Microcks container. + /// + /// + /// + public MicrocksBuilder WithMainArtifacts(params string[] mainArtifacts) + { + if (_mainArtifacts == null) + { + _mainArtifacts = new List(mainArtifacts); + } + else + { + _mainArtifacts.AddRange(mainArtifacts); + } + return this; + } + + /// + /// Set the secondary artifacts to import into the Microcks container. + /// + /// + /// + public MicrocksBuilder WithSecondaryArtifacts(params string[] secondaryArtifacts) + { + if (_secondaryArtifacts == null) + { + _secondaryArtifacts = new List(secondaryArtifacts); + } + else + { + _secondaryArtifacts.AddRange(secondaryArtifacts); + } + return this; + } + + /// + /// Set the secrets to create into the Microcks container. + /// + /// + /// + public MicrocksBuilder WithSecret(params Model.Secret[] secrets) + { + if (_secrets == null) + { + _secrets = new List(secrets); + } + else + { + _secrets.AddRange(secrets); + } + return this; + } +} diff --git a/src/Microcks.Testcontainers/MicrocksConfiguration.cs b/src/Microcks.Testcontainers/MicrocksConfiguration.cs new file mode 100644 index 0000000..81e7e68 --- /dev/null +++ b/src/Microcks.Testcontainers/MicrocksConfiguration.cs @@ -0,0 +1,67 @@ +// +// Copyright The Microcks Authors. +// +// 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. +// +// + +namespace Microcks.Testcontainers; + +/// +public sealed class MicrocksConfiguration : ContainerConfiguration +{ + /// + /// Initializes a new instance of the class. + /// + /// The Microcks config. + public MicrocksConfiguration(object config = null) + { + } + + /// + /// Initializes a new instance of the class. + /// + /// The Docker resource configuration. + public MicrocksConfiguration(IResourceConfiguration resourceConfiguration) + : base(resourceConfiguration) + { + } + + /// + /// Initializes a new instance of the class. + /// + /// The Docker resource configuration. + public MicrocksConfiguration(IContainerConfiguration resourceConfiguration) + : base(resourceConfiguration) + { + } + + /// + /// Initializes a new instance of the class. + /// + /// The Docker resource configuration. + public MicrocksConfiguration(MicrocksConfiguration resourceConfiguration) + : this(new MicrocksConfiguration(), resourceConfiguration) + { + } + + /// + /// Initializes a new instance of the class. + /// + /// The old Docker resource configuration. + /// The new Docker resource configuration. + public MicrocksConfiguration(MicrocksConfiguration oldValue, MicrocksConfiguration newValue) + : base(oldValue, newValue) + { + } +} diff --git a/src/Microcks.Testcontainers/MicrocksContainer.cs b/src/Microcks.Testcontainers/MicrocksContainer.cs new file mode 100644 index 0000000..d1d59c2 --- /dev/null +++ b/src/Microcks.Testcontainers/MicrocksContainer.cs @@ -0,0 +1,125 @@ +// +// Copyright The Microcks Authors. +// +// 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. +// +// + +using System.Threading.Tasks; +namespace Microcks.Testcontainers; + +/// +public sealed class MicrocksContainer : DockerContainer +{ + /// + /// Initializes a new instance of the class. + /// + /// The container configuration. + public MicrocksContainer(MicrocksConfiguration configuration) + : base(configuration) + { + Starting += (_, _) => Logger.LogInformation("MicrocksContainer container is starting, performing configuration."); + Started += (_, _) => Logger.LogInformation("MicrocksContainer container is ready! UI available at {Url}.", GetHttpEndpoint()); + } + + /// + /// Returns the GraphQL Base URL for the Microcks container. + /// + /// + /// + /// + public Uri GetGraphQLMockEndpoint(string name, string version) + { + return new UriBuilder(GetHttpEndpoint()) + { + Path = $"graphql/{name}/{version}" + }.Uri; + } + + /// + /// Returns the gRPC Base URL for the Microcks container. + /// + /// + public Uri GetGrpcMockEndpoint() + { + return new UriBuilder("grpc", Hostname, GetMappedPublicPort(MicrocksBuilder.MicrocksGrpcPort)).Uri; + } + + /// + /// Obtains the HTTP endpoint for the Microcks container. + /// + /// HTTP endpoint address + public Uri GetHttpEndpoint() + { + return new UriBuilder( + Uri.UriSchemeHttp, + Hostname, + GetMappedPublicPort(MicrocksBuilder.MicrocksHttpPort) + ).Uri; + } + + /// + /// Returns the REST Base URL for the Microcks container. + /// + /// + /// + /// + public Uri GetRestMockEndpoint(string name, string version) + { + return new UriBuilder(GetHttpEndpoint()) + { + Path = $"rest/{name}/{version}" + }.Uri; + } + + /// + /// Returns the SOAP Base URL for the Microcks container. + /// + /// + /// + /// + public Uri GetSoapMockEndpoint(string name, string version) + { + return new UriBuilder(GetHttpEndpoint()) + { + Path = $"soap/{name}/{version}" + }.Uri; + } + + /// + /// Import a main artifact into the Microcks container after it has started. + /// + /// + public void ImportAsMainArtifact(string artifact) + { + this.ImportArtifactAsync(artifact, true).GetAwaiter().GetResult(); + } + + /// + /// Import a secondary artifact into the Microcks container after it has started. + /// + /// + public void ImportAsSecondaryArtifact(string artifact) + { + this.ImportArtifactAsync(artifact, false).GetAwaiter().GetResult(); + } + + /// + /// Dispose of the Microcks container. + /// + /// + protected override ValueTask DisposeAsyncCore() + { + return base.DisposeAsyncCore(); + } +} diff --git a/src/Microcks.Testcontainers/MicrocksContainerExtensions.cs b/src/Microcks.Testcontainers/MicrocksContainerExtensions.cs new file mode 100644 index 0000000..9e588ca --- /dev/null +++ b/src/Microcks.Testcontainers/MicrocksContainerExtensions.cs @@ -0,0 +1,179 @@ +// +// Copyright The Microcks Authors. +// +// 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. +// +// + +using Microcks.Testcontainers.Model; +using System.IO; +using System.Net; +using System.Net.Http; +using System.Net.Http.Headers; +using System.Text; +using System.Text.Json; +using System.Threading; +using System.Threading.Tasks; + +namespace Microcks.Testcontainers; + +/// +/// Extensions for MicrocksContainer. +/// +public static class MicrocksContainerExtensions +{ + /// + /// HttpClient to use for Microcks. + /// + public static HttpClient Client => _lazyClient.Value; + private static Lazy _lazyClient = new Lazy(() => new HttpClient() + { + DefaultRequestHeaders = + { + Accept = { MediaTypeWithQualityHeaderValue.Parse("application/json") }, + CacheControl = CacheControlHeaderValue.Parse("no-cache") + } + }); + + /// + /// Test an endpoint with a TestRequest. + /// + /// + /// + /// + /// + public static async Task TestEndpointAsync( + this MicrocksContainer container, TestRequest testRequest) + { + string httpEndpoint = container.GetHttpEndpoint() + "api/tests"; + var content = new StringContent(JsonSerializer.Serialize(testRequest), Encoding.UTF8, "application/json"); + var responseMessage = await Client.PostAsync(httpEndpoint, content); + + if (responseMessage.StatusCode == HttpStatusCode.Created) + { + var responseContent = await responseMessage.Content.ReadAsStringAsync(); + + var testResult = JsonSerializer.Deserialize(responseContent); + var testResultId = testResult.Id; + container.Logger.LogDebug("Test launched with ID: {TestResultId}, new polling for progression", testResultId); + + try + { + await WaitForConditionAsync(async () => !(await RefreshTestResultAsync(httpEndpoint, testResultId)).InProgress, + atMost: TimeSpan.FromMilliseconds(1000).Add(testRequest.Timeout), + delay: TimeSpan.FromMilliseconds(100), + interval: TimeSpan.FromMilliseconds(200)); + + } + catch (TaskCanceledException) + { + container.Logger.LogWarning("Test timeout reached, stopping polling"); + } + + return await RefreshTestResultAsync(httpEndpoint, testResultId); + } + else + { + throw new Exception("Couldn't launch on new test on Microcks. Please check Microcks container logs"); + } + } + + private static async Task RefreshTestResultAsync(string httpEndpoint, string testResultId) + { + var result = await Client.GetAsync(httpEndpoint + "/" + testResultId); + var jsonResult = await result.Content.ReadAsStringAsync(); + var testResult = JsonSerializer.Deserialize(jsonResult); + return testResult; + } + + private static async Task WaitForConditionAsync(Func> condition, TimeSpan atMost, TimeSpan delay, TimeSpan interval) + { + // Cancel after atMost + using var cancellationTokenSource = new CancellationTokenSource(atMost); + + // Delay before first check + await Task.Delay(delay, cancellationTokenSource.Token); + + // Polling + while (!await condition()) + { + if (cancellationTokenSource.Token.IsCancellationRequested) + { + throw new TaskCanceledException(); + } + await Task.Delay(interval, cancellationTokenSource.Token); + } + } + + internal static async Task ImportArtifactAsync(this MicrocksContainer container, string artifact, bool mainArtifact) + { + string url = $"{container.GetHttpEndpoint()}api/artifact/upload" + (mainArtifact ? "" : "?mainArtifact=false"); + var result = await container.UploadFileToMicrocksAsync(artifact, url); + if (result.StatusCode != HttpStatusCode.Created) + { + throw new Exception($"Artifact has not been correctly imported: {result.StatusCode}"); + } + container.Logger.LogInformation($"Artifact {artifact} has been imported"); + } + + internal static async Task UploadFileToMicrocksAsync(this MicrocksContainer container, string filepath, string url) + { + using (var form = new MultipartFormDataContent()) + { + using var snapContent = new ByteArrayContent(File.ReadAllBytes(filepath)); + snapContent.Headers.ContentType = MediaTypeHeaderValue.Parse("application/json"); + form.Add(snapContent, "file", Path.GetFileName(filepath)); + + return await Client.PostAsync(url, form); + } + } + + internal static async Task ImportSnapshotAsync(this MicrocksContainer container, string snapshot) + { + string url = $"{container.GetHttpEndpoint()}api/import"; + var result = await container.UploadFileToMicrocksAsync(snapshot, url); + + if (result.StatusCode != HttpStatusCode.Created) + { + throw new Exception($"Snapshot has not been correctly imported: {result.StatusCode}"); + } + container.Logger.LogInformation($"Snapshot {snapshot} has been imported"); + } + + internal static async Task CreateSecretAsync(this MicrocksContainer container, Model.Secret secret) + { + string url = $"{container.GetHttpEndpoint()}api/secrets"; + var content = new StringContent(JsonSerializer.Serialize(secret), Encoding.UTF8, "application/json"); + + var result = await Client.PostAsync(url, content); + + if (result.StatusCode != HttpStatusCode.Created) + { + throw new Exception("Secret has not been correctly created"); + } + container.Logger.LogInformation($"Secret {secret.Name} has been created"); + } + + internal static async Task DownloadArtifactAsync(this MicrocksContainer container, string remoteArtifactUrl, bool main) + { + var content = new StringContent("mainArtifact=" + main + "&url=" + remoteArtifactUrl, Encoding.UTF8, "application/x-www-form-urlencoded"); + var result = await Client + .PostAsync($"{container.GetHttpEndpoint()}api/artifact/download", content); + + if (result.StatusCode != HttpStatusCode.Created) + { + throw new Exception("Artifact has not been correctly downloaded"); + } + container.Logger.LogInformation($"Artifact {remoteArtifactUrl} has been downloaded"); + } +} diff --git a/src/Microcks.Testcontainers/Model/Header.cs b/src/Microcks.Testcontainers/Model/Header.cs new file mode 100644 index 0000000..f8a2f4e --- /dev/null +++ b/src/Microcks.Testcontainers/Model/Header.cs @@ -0,0 +1,37 @@ +// +// Copyright The Microcks Authors. +// +// 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. +// +// + +using Microcks.Testcontainers.Converter; +using System.Text.Json.Serialization; + +#pragma warning disable CS1591 // Missing XML comment for publicly visible type or member + +namespace Microcks.Testcontainers.Model; + +/// +/// Microcks Contrat for a header. +/// +public class Header +{ + [JsonPropertyName("name")] + public string Name { get; set; } + + [JsonPropertyName("values")] + [JsonConverter(typeof(ArrayToStringConverter))] + public string Values { get; set; } + +} diff --git a/src/Microcks.Testcontainers/Model/OAuth2ClientContext.cs b/src/Microcks.Testcontainers/Model/OAuth2ClientContext.cs new file mode 100644 index 0000000..eb68859 --- /dev/null +++ b/src/Microcks.Testcontainers/Model/OAuth2ClientContext.cs @@ -0,0 +1,23 @@ +// +// Copyright The Microcks Authors. +// +// 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. +// +// + +namespace Microcks.Testcontainers.Model; + +#pragma warning disable CS1591 // Missing XML comment for publicly visible type or member +public class OAuth2ClientContext +{ +} diff --git a/src/Microcks.Testcontainers/Model/Secret.cs b/src/Microcks.Testcontainers/Model/Secret.cs new file mode 100644 index 0000000..61be256 --- /dev/null +++ b/src/Microcks.Testcontainers/Model/Secret.cs @@ -0,0 +1,47 @@ +// +// Copyright The Microcks Authors. +// +// 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. +// +// + +using System.Text.Json.Serialization; + +namespace Microcks.Testcontainers.Model; +#pragma warning disable CS1591 // Missing XML comment for publicly visible type or member +/// +/// Microcks Contrat for a secret. +/// +public class Secret +{ + [JsonPropertyName("name")] + public string Name { get; set; } + + [JsonPropertyName("description")] + public string Description { get; set; } + + [JsonPropertyName("username")] + public string Username { get; set; } + + [JsonPropertyName("password")] + public string Password { get; set; } + + [JsonPropertyName("token")] + public string Token { get; set; } + + [JsonPropertyName("tokenHeader")] + public string TokenHeader { get; set; } + + [JsonPropertyName("caCertPerm")] + public string CaCertPem { get; set; } +} diff --git a/src/Microcks.Testcontainers/Model/SecretBuilder.cs b/src/Microcks.Testcontainers/Model/SecretBuilder.cs new file mode 100644 index 0000000..1d2c9e5 --- /dev/null +++ b/src/Microcks.Testcontainers/Model/SecretBuilder.cs @@ -0,0 +1,93 @@ +// +// Copyright The Microcks Authors. +// +// 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. +// +// + +namespace Microcks.Testcontainers.Model; +#pragma warning disable CS1591 // Missing XML comment for publicly visible type or member +/// +/// Builder for . +/// +public class SecretBuilder +{ + private string _name; + private string _token; + private string _description; + private string _caCertPem = null; + private string _tokenHeader; + private string _password; + private string _username; + + public SecretBuilder WithName(string name) + { + _name = name; + return this; + } + + public SecretBuilder WithDescription(string description) + { + _description = description; + return this; + } + + public SecretBuilder WithToken(string token) + { + _token = token; + return this; + } + + public SecretBuilder WithUsername(string username) + { + _username = username; + return this; + } + + public SecretBuilder WithPassword(string password) + { + _password = password; + return this; + } + + public SecretBuilder WithTokenHeader(string tokenHeader) + { + _tokenHeader = tokenHeader; + return this; + } + + public SecretBuilder WithCaCertPem(string caCertPem) + { + _caCertPem = caCertPem; + return this; + } + + public Secret Build() + { + if (_name == null) + { + throw new ArgumentNullException("Name is required"); + } + + return new Secret() + { + Name = _name, + Description = _description, + Username = _username, + Password = _password, + Token = _token, + CaCertPem = _caCertPem, + TokenHeader = _tokenHeader + }; + } +} diff --git a/src/Microcks.Testcontainers/Model/TestCaseResult.cs b/src/Microcks.Testcontainers/Model/TestCaseResult.cs new file mode 100644 index 0000000..8bf0f04 --- /dev/null +++ b/src/Microcks.Testcontainers/Model/TestCaseResult.cs @@ -0,0 +1,38 @@ +// +// Copyright The Microcks Authors. +// +// 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. +// +// + +using System.Text.Json.Serialization; + +namespace Microcks.Testcontainers.Model; +#pragma warning disable CS1591 // Missing XML comment for publicly visible type or member +/// +/// TestCaseResult. +/// +public class TestCaseResult +{ + [JsonPropertyName("success")] + public bool Success { get; set; } + + [JsonPropertyName("elapsedTime")] + public int ElapsedTime { get; set; } + + [JsonPropertyName("operationName")] + public string OperationName { get; set; } + + [JsonPropertyName("testStepResults")] + public List TestStepResults { get; set; } +} diff --git a/src/Microcks.Testcontainers/Model/TestRequest.cs b/src/Microcks.Testcontainers/Model/TestRequest.cs new file mode 100644 index 0000000..1b96158 --- /dev/null +++ b/src/Microcks.Testcontainers/Model/TestRequest.cs @@ -0,0 +1,49 @@ +// +// Copyright The Microcks Authors. +// +// 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. +// +// + +using Microcks.Testcontainers.Converter; +using System.Text.Json.Serialization; + +namespace Microcks.Testcontainers.Model; +#pragma warning disable CS1591 // Missing XML comment for publicly visible type or member +/// +/// TestRequest Model for Microcks. +/// +public class TestRequest +{ + [JsonPropertyName("serviceId")] + public string ServiceId { get; set; } + + [JsonPropertyName("runnerType")] + public TestRunnerType RunnerType { get; set; } + + [JsonPropertyName("testEndpoint")] + public string TestEndpoint { get; set; } + + [JsonPropertyName("timeout")] + [JsonConverter(typeof(TimeSpanToMillisecondsConverter))] + public TimeSpan Timeout { get; set; } + + [JsonPropertyName("filteredOperations")] + public List FilteredOperations { get; set; } + + [JsonPropertyName("operationsHeaders")] + public Dictionary> OperationsHeaders { get; set; } + + [JsonPropertyName("oAuth2Context")] + public OAuth2ClientContext oAuth2Context { get; set; } +} diff --git a/src/Microcks.Testcontainers/Model/TestResult.cs b/src/Microcks.Testcontainers/Model/TestResult.cs new file mode 100644 index 0000000..d2d59bf --- /dev/null +++ b/src/Microcks.Testcontainers/Model/TestResult.cs @@ -0,0 +1,67 @@ +// +// Copyright The Microcks Authors. +// +// 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. +// +// + +using Microcks.Testcontainers.Converter; +using System.Text.Json.Serialization; + +namespace Microcks.Testcontainers.Model; +#pragma warning disable CS1591 // Missing XML comment for publicly visible type or member +/// +/// TestResult model for Microcks. +/// +public class TestResult +{ + [JsonPropertyName("id")] + public string Id { get; set; } + + [JsonPropertyName("version")] + public int Version { get; set; } + + [JsonPropertyName("testNumber")] + public int TestNumber { get; set; } + + [JsonPropertyName("testDate")] + public long TestDate { get; set; } + + [JsonPropertyName("testedEndpoint")] + public string TestedEndpoint { get; set; } + + [JsonPropertyName("serviceId")] + public string ServiceId { get; set; } + + [JsonConverter(typeof(TimeSpanToMillisecondsConverter))] + [JsonPropertyName("timeout")] + public TimeSpan Timeout { get; set; } + + [JsonPropertyName("elapsedTime")] + public int ElapsedTime { get; set; } + + [JsonPropertyName("success")] + public bool Success { get; set; } + + [JsonPropertyName("inProgress")] + public bool InProgress { get; set; } + + [JsonPropertyName("runnerType")] + public TestRunnerType RunnerType { get; set; } + + [JsonPropertyName("testCaseResults")] + public List TestCaseResults { get; set; } + + [JsonPropertyName("operationsHeaders")] + public Dictionary> OperationsHeaders { get; set; } +} diff --git a/src/Microcks.Testcontainers/Model/TestRunnerType.cs b/src/Microcks.Testcontainers/Model/TestRunnerType.cs new file mode 100644 index 0000000..6e98710 --- /dev/null +++ b/src/Microcks.Testcontainers/Model/TestRunnerType.cs @@ -0,0 +1,38 @@ +// +// Copyright The Microcks Authors. +// +// 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. +// +// + +using System.Text.Json.Serialization; + +namespace Microcks.Testcontainers.Model; + +#pragma warning disable CS1591 // Missing XML comment for publicly visible type or member + +/// +/// TestRunnerType for Microcks. +/// +[JsonConverter(typeof(JsonStringEnumConverter))] +public enum TestRunnerType +{ + HTTP, + SOAP_HTTP, + SOAP_UI, + POSTMAN, + OPEN_API_SCHEMA, + ASYNC_API_SCHEMA, + GRPC_PROTOBUF, + GRAPHQL_SCHEMA +} diff --git a/src/Microcks.Testcontainers/Model/TestStepResult.cs b/src/Microcks.Testcontainers/Model/TestStepResult.cs new file mode 100644 index 0000000..9cfd5eb --- /dev/null +++ b/src/Microcks.Testcontainers/Model/TestStepResult.cs @@ -0,0 +1,38 @@ +// +// Copyright The Microcks Authors. +// +// 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. +// +// + +using System.Text.Json.Serialization; + +namespace Microcks.Testcontainers.Model; +#pragma warning disable CS1591 // Missing XML comment for publicly visible type or member +public class TestStepResult +{ + [JsonPropertyName("success")] + public bool Success { get; set; } + + [JsonPropertyName("elapsedTime")] + public int ElapsedTime { get; set; } + + [JsonPropertyName("requestName")] + public string RequestName { get; set; } + + [JsonPropertyName("eventMessageName")] + public string EventMessageName { get; set; } + + [JsonPropertyName("message")] + public string Message { get; set; } +} diff --git a/src/Microcks.Testcontainers/Usings.cs b/src/Microcks.Testcontainers/Usings.cs new file mode 100644 index 0000000..be05ed8 --- /dev/null +++ b/src/Microcks.Testcontainers/Usings.cs @@ -0,0 +1,25 @@ +// +// Copyright The Microcks Authors. +// +// 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. +// +// + +global using Docker.DotNet.Models; +global using DotNet.Testcontainers.Builders; +global using DotNet.Testcontainers.Configurations; +global using DotNet.Testcontainers.Containers; +global using Microsoft.Extensions.Logging; +global using System; +global using System.Collections.Generic; +global using System.Linq; diff --git a/tests/Microcks.Testcontainers.Tests/Microcks.Testcontainers.Tests.csproj b/tests/Microcks.Testcontainers.Tests/Microcks.Testcontainers.Tests.csproj new file mode 100644 index 0000000..40c943b --- /dev/null +++ b/tests/Microcks.Testcontainers.Tests/Microcks.Testcontainers.Tests.csproj @@ -0,0 +1,33 @@ + + + net8.0 + false + false + $(NoWarn);CS1591 + + + + + + + + + + + + + + + PreserveNewest + + + PreserveNewest + + + PreserveNewest + + + PreserveNewest + + + \ No newline at end of file diff --git a/tests/Microcks.Testcontainers.Tests/MicrocksContractTestingFunctionalityTests.cs b/tests/Microcks.Testcontainers.Tests/MicrocksContractTestingFunctionalityTests.cs new file mode 100644 index 0000000..9bc828d --- /dev/null +++ b/tests/Microcks.Testcontainers.Tests/MicrocksContractTestingFunctionalityTests.cs @@ -0,0 +1,165 @@ +// +// Copyright The Microcks Authors. +// +// 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. +// +// + +using DotNet.Testcontainers.Builders; +using DotNet.Testcontainers.Containers; +using DotNet.Testcontainers.Networks; +using FluentAssertions; +using Microcks.Testcontainers; +using Microcks.Testcontainers.Model; +using System; +using System.Collections.Generic; +using System.Net; + +namespace Testcontainers.Microcks.Tests; + +public sealed class MicrocksContractTestingFunctionalityTests : IAsyncLifetime +{ + private readonly INetwork _network = new NetworkBuilder().Build(); + private readonly MicrocksContainer _microcksContainer; + private readonly IContainer _badImpl; + private readonly IContainer _goodImpl; + + + private static readonly string BAD_PASTRY_IMAGE = "quay.io/microcks/contract-testing-demo:01"; + private static readonly string GOOD_PASTRY_IMAGE = "quay.io/microcks/contract-testing-demo:02"; + + public MicrocksContractTestingFunctionalityTests() + { + _microcksContainer = new MicrocksBuilder() + .WithNetwork(_network) + .Build(); + + _badImpl = new ContainerBuilder() + .WithImage(BAD_PASTRY_IMAGE) + .WithNetwork(_network) + .WithNetworkAliases("bad-impl") + .WithWaitStrategy(Wait.ForUnixContainer().UntilMessageIsLogged(".*Example app listening on port 3001.*")) + .Build(); + + _goodImpl = new ContainerBuilder() + .WithImage(GOOD_PASTRY_IMAGE) + .WithNetwork(_network) + .WithNetworkAliases("good-impl") + .WithWaitStrategy(Wait.ForUnixContainer().UntilMessageIsLogged(".*Example app listening on port 3002.*")) + .Build(); + } + + public Task DisposeAsync() + { + return Task.WhenAll( + _microcksContainer.DisposeAsync().AsTask(), + _badImpl.DisposeAsync().AsTask(), + _goodImpl.DisposeAsync().AsTask(), + _network.DisposeAsync().AsTask() + ); + } + + public Task InitializeAsync() + { + _microcksContainer.Started += + (_, _) => _microcksContainer.ImportAsMainArtifact("apipastries-openapi.yaml"); + + return Task.WhenAll( + _microcksContainer.StartAsync(), + _badImpl.StartAsync(), + _goodImpl.StartAsync() + ); + } + + [Fact] + public void ShouldConfigRetrieval() + { + var uriBuilder = new UriBuilder(_microcksContainer.GetHttpEndpoint()) + { + Path = "/api/keycloak/config" + }; + + Given() + .When() + .Get(uriBuilder.ToString()) + .Then() + .StatusCode(HttpStatusCode.OK); + } + + [Fact] + public async Task ShouldReturnSuccess_WhenGoodImplementation() + { + var badTestRequest = new TestRequest + { + ServiceId = "API Pastries:0.0.1", + RunnerType = TestRunnerType.OPEN_API_SCHEMA, + TestEndpoint = "http://bad-impl:3001", + Timeout = TimeSpan.FromMilliseconds(2000) + }; + + // First test should fail with validation failure messages. + TestResult badTestResult = await _microcksContainer.TestEndpointAsync(badTestRequest); + badTestResult.Success.Should().BeFalse(); + badTestResult.TestedEndpoint.Should().Be("http://bad-impl:3001"); + badTestResult.TestCaseResults.Should().HaveCount(3); + badTestResult.TestCaseResults[0].TestStepResults[0].Message.Should().Contain("object has missing required properties"); + + // Switch endpoint to good implementation + var goodTestRequest = new TestRequest + { + ServiceId = "API Pastries:0.0.1", + RunnerType = TestRunnerType.OPEN_API_SCHEMA, + TestEndpoint = "http://good-impl:3002", + Timeout = TimeSpan.FromMilliseconds(2000) + }; + TestResult goodTestResult = await _microcksContainer.TestEndpointAsync(goodTestRequest); + goodTestResult.Success.Should().BeTrue(); + goodTestResult.TestedEndpoint.Should().Be("http://good-impl:3002"); + goodTestResult.TestCaseResults.Should().HaveCount(3); + goodTestResult.TestCaseResults[0].TestStepResults[0].Message.Should().BeEmpty(); + + // Test avec un header + var goodTestRequestWithHeader = new TestRequest + { + ServiceId = "API Pastries:0.0.1", + RunnerType = TestRunnerType.OPEN_API_SCHEMA, + TestEndpoint = "http://good-impl:3002", + Timeout = TimeSpan.FromSeconds(2), + OperationsHeaders = new Dictionary>() + { + { + "GET /pastries", + new List
+ { + new() { + Name = "X-Custom-Header-1", + Values = "value1,value2,value3" + } + } + } + } + }; + + TestResult goodTestResultWithHeader = await _microcksContainer.TestEndpointAsync(goodTestRequestWithHeader); + goodTestResultWithHeader.Success.Should().BeTrue(); + goodTestResultWithHeader.TestedEndpoint.Should().Be("http://good-impl:3002"); + goodTestResultWithHeader.TestCaseResults.Should().HaveCount(3); + goodTestResultWithHeader.TestCaseResults[0].TestStepResults[0].Message.Should().BeEmpty(); + goodTestResultWithHeader.OperationsHeaders.Should().HaveCount(1); + goodTestResultWithHeader.OperationsHeaders.Should().ContainKey("GET /pastries"); + goodTestResultWithHeader.OperationsHeaders["GET /pastries"].Should().HaveCount(1); + var header = goodTestResultWithHeader.OperationsHeaders["GET /pastries"][0]; + header.Name.Should().Be("X-Custom-Header-1"); + header.Values.Split(",").Should().BeEquivalentTo(["value1", "value2", "value3"]); + } +} diff --git a/tests/Microcks.Testcontainers.Tests/MicrocksMockingFunctionalityTest.cs b/tests/Microcks.Testcontainers.Tests/MicrocksMockingFunctionalityTest.cs new file mode 100644 index 0000000..b9fe1bb --- /dev/null +++ b/tests/Microcks.Testcontainers.Tests/MicrocksMockingFunctionalityTest.cs @@ -0,0 +1,146 @@ +// +// Copyright The Microcks Authors. +// +// 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. +// +// + +using FluentAssertions; +using NHamcrest; +using NHamcrest.Core; +using RestAssured.Response; +using System; +using System.IO; +using System.Net; +using System.Text.Json; + +namespace Microcks.Testcontainers.Tests; + +public sealed class MicrocksMockingFunctionalityTest : IAsyncLifetime +{ + private readonly MicrocksContainer _microcksContainer = new MicrocksBuilder() + .WithSnapshots("microcks-repository.json") + .WithMainArtifacts("apipastries-openapi.yaml", Path.Combine("subdir", "weather-forecast-openapi.yaml")) + .WithMainRemoteArtifacts("https://raw.githubusercontent.com/microcks/microcks/master/samples/APIPastry-openapi.yaml") + .WithSecondaryArtifacts("apipastries-postman-collection.json") + .Build(); + + public Task DisposeAsync() + { + return _microcksContainer.DisposeAsync().AsTask(); + } + + public Task InitializeAsync() + { + return _microcksContainer.StartAsync(); + } + + [Fact] + public void ShouldConfigureMockEndpoints() + { + string baseWsUrl = $"{_microcksContainer.GetSoapMockEndpoint("Pastries Service", "1.0")}"; + baseWsUrl.Should().Be($"{_microcksContainer.GetHttpEndpoint()}soap/Pastries Service/1.0"); + + string baseApiUrl = $"{_microcksContainer.GetRestMockEndpoint("API Pastries", "0.0.1")}"; + baseApiUrl.Should().Be($"{_microcksContainer.GetHttpEndpoint()}rest/API Pastries/0.0.1"); + + string baseGraphUrl = $"{_microcksContainer.GetGraphQLMockEndpoint("Pastries Graph", "1")}"; + baseGraphUrl.Should().Be($"{_microcksContainer.GetHttpEndpoint()}graphql/Pastries Graph/1"); + + string baseGrpcUrl = $"{_microcksContainer.GetGrpcMockEndpoint()}"; + baseGrpcUrl.Should().Be($"grpc://{_microcksContainer.Hostname}:{_microcksContainer.GetMappedPublicPort(MicrocksBuilder.MicrocksGrpcPort)}/"); + } + + [Fact] + public void ShouldConfigRetrieval() + { + var uriBuilder = new UriBuilder(_microcksContainer.GetHttpEndpoint()) + { + Path = "/api/keycloak/config" + }; + + Given() + .When() + .Get(uriBuilder.ToString()) + .Then() + .StatusCode(HttpStatusCode.OK); + } + + [Fact] + public async Task ShouldAvailableServices() + { + var uriBuilder = new UriBuilder(_microcksContainer.GetHttpEndpoint()) + { + Path = "/api/services" + }; + + var verifiableResponse = Given() + .Log(RestAssured.Request.Logging.RequestLogLevel.All) + .When() + .Get(uriBuilder.ToString()) + .Then() + .StatusCode(HttpStatusCode.OK); + + // newtonsoft json jsonpath $.length is not supported + var services = await verifiableResponse + .Extract() + .Response().Content.ReadAsStringAsync(); + + var document = JsonDocument.Parse(services); + document.RootElement.EnumerateArray().Should().HaveCount(7); + + + verifiableResponse.Body("$[0:].name", Has.Items( + Is.EqualTo("Petstore API"), + Is.EqualTo("HelloService Mock"), + Is.EqualTo("io.github.microcks.grpc.hello.v1.HelloService"), + Is.EqualTo("Movie Graph API"), + Is.EqualTo("API Pastry - 2.0"), + Is.EqualTo("API Pastries"), + Is.EqualTo("WeatherForecast API") + ), + VerifyAs.Json); + } + + [Fact] + public void ShouldMockVariousCapabilities() + { + var pastries = _microcksContainer.GetRestMockEndpoint("API Pastries", "0.0.1"); + + Given() + .When() + .Get($"{pastries}/pastries/Millefeuille") + .Then() + .StatusCode(HttpStatusCode.OK) + .Body("$.name", IsEqualMatcher.EqualTo("Millefeuille")); + + + // Vérifier que le mock de l'API Pastry est bien disponible + Given() + .When() + .Get($"{pastries}/pastries/Eclair Chocolat") + .Then() + .StatusCode(HttpStatusCode.OK) + .Body("$.name", IsEqualMatcher.EqualTo("Eclair Chocolat")); + + var baseApiUrl = _microcksContainer.GetRestMockEndpoint("API Pastry - 2.0", "2.0.0"); + + Given() + .When() + .Get($"{baseApiUrl}" + "/pastry/Millefeuille") + .Then() + .StatusCode(HttpStatusCode.OK) + .Body("$.name", IsEqualMatcher.EqualTo("Millefeuille")); + } + +} diff --git a/tests/Microcks.Testcontainers.Tests/MicrocksSecretCreationTests.cs b/tests/Microcks.Testcontainers.Tests/MicrocksSecretCreationTests.cs new file mode 100644 index 0000000..8a03e8c --- /dev/null +++ b/tests/Microcks.Testcontainers.Tests/MicrocksSecretCreationTests.cs @@ -0,0 +1,79 @@ +// +// Copyright The Microcks Authors. +// +// 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. +// +// + +using FluentAssertions; +using Microcks.Testcontainers; +using NHamcrest; +using System; +using System.Net; +using System.Text.Json; +using Microcks.Testcontainers.Model; + +namespace Testcontainers.Microcks.Tests; + +public sealed class MicrocksSecretCreationTests : IAsyncLifetime +{ + private readonly MicrocksContainer _microcksContainer = new MicrocksBuilder() + .WithSecret(new SecretBuilder().WithName("my-secret").WithToken("abc-123-xyz").Build()) + .Build(); + + public Task DisposeAsync() + { + return _microcksContainer.DisposeAsync().AsTask(); + } + + public Task InitializeAsync() + { + return _microcksContainer.StartAsync(); + } + + [Fact] + public async Task ShouldFindSecrets() + { + var result = await Given() + .When() + .Log(RestAssured.Request.Logging.RequestLogLevel.Body) + .Get(_microcksContainer.GetHttpEndpoint() + "api/secrets") + .Then() + .StatusCode(HttpStatusCode.OK) + .And() + .Body("$[0].name", Is.EqualTo("my-secret")) + .And() + .Body("$[0].token", Is.EqualTo("abc-123-xyz")) + .Extract() + .Response().Content.ReadAsStringAsync(); + + var document = JsonDocument.Parse(result); + document.RootElement.EnumerateArray().Should().HaveCount(1); + } + + [Fact] + public void ShouldNotThrowExceptionWhenNameDefined() + { + var secret = new SecretBuilder() + .WithName("my-secret") + .Build(); + secret.Should().NotBeNull(); + secret.Name.Should().Be("my-secret"); + } + + [Fact] + public void ShouldThrowExceptionWhenNameNotDefined() + { + Assert.Throws(() => new SecretBuilder().Build()); + } +} diff --git a/tests/Microcks.Testcontainers.Tests/Usings.cs b/tests/Microcks.Testcontainers.Tests/Usings.cs new file mode 100644 index 0000000..73daa7b --- /dev/null +++ b/tests/Microcks.Testcontainers.Tests/Usings.cs @@ -0,0 +1,20 @@ +// +// Copyright The Microcks Authors. +// +// 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. +// +// + +global using System.Threading.Tasks; +global using Xunit; +global using static RestAssured.Dsl; diff --git a/tests/Microcks.Testcontainers.Tests/apipastries-openapi.yaml b/tests/Microcks.Testcontainers.Tests/apipastries-openapi.yaml new file mode 100644 index 0000000..40d5be4 --- /dev/null +++ b/tests/Microcks.Testcontainers.Tests/apipastries-openapi.yaml @@ -0,0 +1,191 @@ +--- +openapi: 3.0.2 +info: + title: API Pastries + version: 0.0.1 + description: API definition of API Pastry sample app + contact: + name: Laurent Broudoux + url: http://github.com/lbroudoux + email: laurent.broudoux@gmail.com + license: + name: MIT License + url: https://opensource.org/licenses/MIT +paths: + /pastries: + summary: Global operations on pastries + get: + tags: + - pastry + parameters: + - name: size + description: pastry size + schema: + type: string + in: query + required: true + examples: + pastries_s: + value: S + pastries_m: + value: M + pastries_l: + value: L + responses: + "200": + content: + application/json: + schema: + type: array + items: + $ref: '#/components/schemas/Pastry' + examples: + pastries_s: + value: + - name: Tartelette Fraise + description: Delicieuse Tartelette aux Fraises fraiches + size: S + price: 2 + status: available + pastries_m: + value: + - name: Divorces + description: Delicieux Divorces pas calorique du tout + size: M + price: 2.8 + status: available + - name: Eclair Cafe + description: Delicieux Eclair au Cafe pas calorique du tout + size: M + price: 2.5 + status: available + pastries_l: + value: + - name: Baba Rhum + description: Delicieux Baba au Rhum pas calorique du tout + size: L + price: 3.2 + status: available + - name: Millefeuille + description: Delicieux Millefeuille pas calorique du tout + size: L + price: 4.4 + status: available + description: Get list of pastries by size + operationId: GetPastriesBySize + summary: Get list of pastries by size + /pastries/{name}: + summary: Specific operation on pastry + get: + parameters: + - examples: + Eclair Cafe: + value: Eclair Cafe + Millefeuille: + value: Millefeuille + name: name + description: pastry name + schema: + type: string + in: path + required: true + responses: + "200": + content: + application/json: + schema: + $ref: '#/components/schemas/Pastry' + examples: + Eclair Cafe: + value: + name: Eclair Cafe + description: Delicieux Eclair au Cafe pas calorique du tout + size: M + price: 2.5 + status: available + Millefeuille: + value: + name: Millefeuille + description: Delicieux Millefeuille pas calorique du tout + size: L + price: 4.4 + status: available + description: Pastry with specified name + operationId: GetPastryByName + summary: Get Pastry by name + description: Get Pastry by name + patch: + requestBody: + content: + application/json: + schema: + $ref: '#/components/schemas/Pastry' + examples: + Eclair Cafe: + value: + price: 2.6 + required: true + parameters: + - examples: + Eclair Cafe: + value: Eclair Cafe + name: name + description: pastry name + schema: + type: string + in: path + required: true + responses: + "200": + content: + application/json: + schema: + $ref: '#/components/schemas/Pastry' + examples: + Eclair Cafe: + value: + name: Eclair Cafe + description: Delicieux Eclair au Cafe pas calorique du tout + size: M + price: 2.6 + status: available + description: Changed pastry + operationId: PatchPastry + summary: Patch existing pastry + parameters: + - name: name + description: pastry name + schema: + type: string + in: path + required: true +components: + schemas: + Pastry: + title: Root Type for Pastry + description: The root of the Pastry type's schema. + type: object + properties: + name: + description: Name of this pastry + type: string + description: + description: A short description of this pastry + type: string + size: + description: Size of pastry (S, M, L) + type: string + price: + description: Price (in USD) of this pastry + type: number + status: + description: Status in stock (available, out_of_stock) + type: string + required: + - name + - price + - status + additionalProperties: false +tags: +- name: pastry + description: Pastry resource diff --git a/tests/Microcks.Testcontainers.Tests/apipastries-postman-collection.json b/tests/Microcks.Testcontainers.Tests/apipastries-postman-collection.json new file mode 100644 index 0000000..e8721be --- /dev/null +++ b/tests/Microcks.Testcontainers.Tests/apipastries-postman-collection.json @@ -0,0 +1,182 @@ +{ + "info": { + "_postman_id": "3cb5af80-dc32-4b6b-87d5-f81307bc71b6", + "name": "API Pastries", + "description": "version=0.0.1 - API Pastries collection", + "schema": "https://schema.getpostman.com/json/collection/v2.1.0/collection.json", + "_exporter_id": "1278651", + "_collection_link": "https://www.postman.com/lbroudoux/workspace/public-workspace/collection/1278651-3cb5af80-dc32-4b6b-87d5-f81307bc71b6?action=share&creator=1278651&source=collection_link" + }, + "item": [ + { + "name": "pastries", + "item": [ + { + "name": "List pastries by size", + "event": [ + { + "listen": "test", + "script": { + "exec": [ + "var expectedSize = pm.globals.get(\"size\");", + "", + "pm.test(\"Valid size in response pastries\", function () {", + " var jsonData = pm.response.json();", + " pm.expect(jsonData).to.be.an(\"array\");", + " jsonData.forEach(pastry => pm.expect(pastry.size).to.eql(expectedSize));", + "});", + "" + ], + "type": "text/javascript" + } + } + ], + "request": { + "method": "GET", + "header": [], + "url": { + "raw": "http://${pastries.base}/pastries?size=M", + "protocol": "http", + "host": [ + "${pastries", + "base}" + ], + "path": [ + "pastries" + ], + "query": [ + { + "key": "size", + "value": "M", + "description": "Size of selected pastries" + } + ] + } + }, + "response": [] + }, + { + "name": "Get pastry by name", + "event": [ + { + "listen": "test", + "script": { + "exec": [ + "var expectedName = pm.globals.get(\"name\");", + "", + "pm.test(\"Valid name in response pastry\", function () {", + " var pastry = pm.response.json();", + " pm.expect(pastry).to.be.an(\"object\");", + " pm.expect(pastry.name).to.eql(expectedName);", + "});" + ], + "type": "text/javascript" + } + } + ], + "request": { + "method": "GET", + "header": [], + "url": { + "raw": "http:///pastries/:name", + "protocol": "http", + "path": [ + "pastries", + ":name" + ], + "variable": [ + { + "key": "name", + "value": "" + } + ] + } + }, + "response": [ + { + "name": "Eclair Chocolat", + "originalRequest": { + "method": "GET", + "header": [], + "url": { + "raw": "http:///pastry/:name", + "protocol": "http", + "path": [ + "pastry", + ":name" + ], + "variable": [ + { + "key": "name", + "value": "Eclair Chocolat" + } + ] + } + }, + "_postman_previewlanguage": "json", + "header": [ + { + "key": "Content-Type", + "value": "application/json", + "name": "Content-Type", + "description": "", + "type": "text" + } + ], + "cookie": [], + "body": "{\n \"name\": \"Eclair Chocolat\",\n \"description\": \"Delicieux Eclair au Chocolat pas calorique du tout\",\n \"size\": \"M\",\n \"price\": 2.4,\n \"status\": \"unknown\"\n}" + } + ] + }, + { + "name": "Update pastry", + "event": [ + { + "listen": "test", + "script": { + "exec": [ + "var expectedPrice = JSON.parse(pm.request.body.raw).price;", + "", + "pm.test(\"Valid price in response pastry\", function () {", + " var pastry = pm.response.json();", + " pm.expect(pastry).to.be.an(\"object\");", + " pm.expect(pastry.price).to.eql(expectedPrice);", + "});" + ], + "type": "text/javascript" + } + } + ], + "request": { + "method": "PATCH", + "header": [], + "body": { + "mode": "raw", + "raw": "", + "options": { + "raw": { + "language": "json" + } + } + }, + "url": { + "raw": "http:///pastries/:name", + "protocol": "http", + "path": [ + "pastries", + ":name" + ], + "variable": [ + { + "key": "name", + "value": "" + } + ] + } + }, + "response": [] + } + ] + } + ] +} diff --git a/tests/Microcks.Testcontainers.Tests/microcks-repository.json b/tests/Microcks.Testcontainers.Tests/microcks-repository.json new file mode 100644 index 0000000..7f2e301 --- /dev/null +++ b/tests/Microcks.Testcontainers.Tests/microcks-repository.json @@ -0,0 +1,970 @@ +{ + "services": [ + { + "id": "64b99e83e2dbae25009ded78", + "name": "Petstore API", + "version": "1.0", + "xmlNS": null, + "type": "REST", + "metadata": { + "createdOn": 1689886339993, + "lastUpdate": 1698223274641, + "annotations": null, + "labels": { "domain": "animal" } + }, + "sourceArtifact": "PetstoreAPI-collection.json", + "operations": [ + { + "name": "GET /v2/pet/:petId", + "method": "GET", + "action": null, + "inputName": null, + "outputName": null, + "bindings": null, + "dispatcher": "SCRIPT", + "dispatcherRules": "if (mockRequest.getRequest().getRequestURI().contains(\"/pet/1\")) {\n return \"get-1\";\n} else {\n return \"get-2\";\n}", + "defaultDelay": 0, + "resourcePaths": [ "/v2/pet/:petId" ], + "parameterConstraints": [] + }, + { + "name": "GET /v2/pet/findByStatus", + "method": "GET", + "action": null, + "inputName": null, + "outputName": null, + "bindings": null, + "dispatcher": "URI_PARAMS", + "dispatcherRules": "user_key && status", + "defaultDelay": null, + "resourcePaths": [ "/v2/pet/findByStatus" ], + "parameterConstraints": null + } + ] + }, + { + "id": "64c8deb82777ee53a545ca59", + "name": "HelloService Mock", + "version": "0.9", + "xmlNS": "http://www.example.com/hello", + "type": "SOAP_HTTP", + "metadata": { + "createdOn": 1690885816030, + "lastUpdate": 1694425056344, + "annotations": null, + "labels": { "domain": "samples" } + }, + "sourceArtifact": "HelloService-soapui-project.xml", + "operations": [ + { + "name": "sayHello", + "method": null, + "action": "", + "inputName": "sayHello", + "outputName": "sayHelloResponse", + "bindings": null, + "dispatcher": "SCRIPT", + "dispatcherRules": "import com.eviware.soapui.support.XmlHolder\ndef holder = new XmlHolder( mockRequest.requestContent )\ndef name = holder[\"//name\"]\n\nif (name == \"Andrew\"){\n return \"Andrew Response\"\n} else if (name == \"Karla\"){\n return \"Karla Response\"\n} else {\n return \"World Response\"\n}\n", + "defaultDelay": null, + "resourcePaths": null, + "parameterConstraints": null + } + ] + }, + { + "id": "65c6170eab2f0b1c5c395dcc", + "name": "io.github.microcks.grpc.hello.v1.HelloService", + "version": "v1", + "xmlNS": "io.github.microcks.grpc.hello.v1", + "type": "GRPC", + "metadata": { + "createdOn": 1707480846087, + "lastUpdate": 1707480846087, + "annotations": null, + "labels": { + "domain": "samples", + "status": "GA" + } + }, + "sourceArtifact": "https://raw.githubusercontent.com/microcks/microcks/master/samples/hello-v1.proto", + "operations": [ + { + "name": "greeting", + "method": null, + "action": null, + "inputName": ".io.github.microcks.grpc.hello.v1.HelloRequest", + "outputName": ".io.github.microcks.grpc.hello.v1.HelloResponse", + "bindings": null, + "dispatcher": "JSON_BODY", + "dispatcherRules": "{\n \"exp\": \"/firstname\",\n \"operator\": \"equals\",\n \"cases\": {\n \"Laurent\": \"Laurent\",\n \"default\": \"John\"\n }\n}", + "defaultDelay": null, + "resourcePaths": [ "/greeting" ], + "parameterConstraints": null + } + ] + }, + { + "id": "65fd7a7a1f846c7939d014cf", + "name": "Movie Graph API", + "version": "1.0", + "xmlNS": null, + "type": "GRAPHQL", + "metadata": { + "createdOn": 1711110778807, + "lastUpdate": 1711110778807, + "annotations": null, + "labels": { + "domain": "movie", + "team": "Team A", + "status": "stable" + } + }, + "sourceArtifact": "https://raw.githubusercontent.com/microcks/microcks/master/samples/films.graphql", + "operations": [ + { + "name": "allFilms", + "method": "QUERY", + "action": null, + "inputName": null, + "outputName": "FilmsConnection", + "bindings": null, + "dispatcher": null, + "dispatcherRules": null, + "defaultDelay": null, + "resourcePaths": [ "{{url}}" ], + "parameterConstraints": null + }, + { + "name": "film", + "method": "QUERY", + "action": null, + "inputName": "String", + "outputName": "Film", + "bindings": null, + "dispatcher": "QUERY_ARGS", + "dispatcherRules": "id", + "defaultDelay": null, + "resourcePaths": null, + "parameterConstraints": null + }, + { + "name": "addStar", + "method": "MUTATION", + "action": null, + "inputName": "String", + "outputName": "Film", + "bindings": null, + "dispatcher": "QUERY_ARGS", + "dispatcherRules": "filmId", + "defaultDelay": null, + "resourcePaths": null, + "parameterConstraints": null + }, + { + "name": "addReview", + "method": "MUTATION", + "action": null, + "inputName": "String, Review", + "outputName": "Film", + "bindings": null, + "dispatcher": "JSON_BODY", + "dispatcherRules": "{\n \"exp\": \"/filmId\",\n \"operator\": \"equals\",\n \"cases\": {\n \"ZmlsbXM6Mg==\": \"addReview to ZmlsbXM6Mg==\",\n \"default\": \"ZmlsbXM6Mg==\"\n }\n}", + "defaultDelay": null, + "resourcePaths": [ "addReview" ], + "parameterConstraints": null + } + ] + } + ], + "resources": [ + { + "id": "64c8deb82777ee53a545ca5a", + "name": "HelloService Mock-0.9.xml", + "path": null, + "content": "\nfile:/Users/lbroudou/Development/github/microcks/samples/HelloService.wsdl\n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n]]>http://schemas.xmlsoap.org/wsdl/http://lbroudoux-OSX.local:8088/mockHelloServicehttp://localhost:8080/services/HelloService<xml-fragment/>UTF-8http://localhost:8080/soap/HelloService Mock/0.9/\n \n \n \n Karla\n \n \n]]>No AuthorizationSEQUENTIALHelloServicesayHello<xml-fragment/>UTF-8http://:8088/mockHelloService\n \n \n \n Andrew\n \n \n]]>200declare namespace ser='http://www.example.com/hello';\n//ser:sayHelloResponse/sayHello<sayHello>Hello Andrew !</sayHello>false500No AuthorizationHelloServicesayHello<xml-fragment/>UTF-8http://localhost:8080/services/HelloService\n \n \n \n\t\tKarla\n \n \n]]>No AuthorizationHelloServicesayHello<xml-fragment/>UTF-8http://lbroudoux-OSX.local:8088/mockHelloService\n \n \n \n\t World\n \n \n]]>500No Authorizationfalseversion0.9Response 1SCRIPTimport com.eviware.soapui.support.XmlHolder\ndef holder = new XmlHolder( mockRequest.requestContent )\ndef name = holder[\"//name\"]\n\nif (name == \"Andrew\"){\n return \"Andrew Response\"\n} else if (name == \"Karla\"){\n return \"Karla Response\"\n} else {\n return \"World Response\"\n}\n\n \n \n \n Hello Andrew !\n \n \n]]>\n \n \n \n Hello Karla !\n \n \n]]>\n \n \n \n \n soapenv:Sender\n \n rpc:BadArguments\n \n \n \n Processing error\n \n \n \n 999\n \n \n \n \n]]>Andrewdeclare namespace ser='http://www.example.com/hello';\n//ser:sayHello/nameAndrewAndrew ResponseKarladeclare namespace ser='http://www.example.com/hello';\n//ser:sayHello/nameKarlaKarla Response", + "type": "SOAP_UI_PROJECT", + "serviceId": "64c8deb82777ee53a545ca59", + "sourceArtifact": "HelloService-soapui-project.xml", + "operations": null + }, + { + "id": "64c8deb82777ee53a545ca5b", + "name": "HelloService Mock-0.9.wsdl", + "path": null, + "content": "\n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n", + "type": "WSDL", + "serviceId": "64c8deb82777ee53a545ca59", + "sourceArtifact": "HelloService-soapui-project.xml", + "operations": null + }, + { + "id": "6527f81898eb0d2f130f2b4b", + "name": "Petstore API-1.0.json", + "path": null, + "content": "{\n\t\"variables\": [],\n\t\"info\": {\n\t\t\"name\": \"Petstore API\",\n\t\t\"_postman_id\": \"c0bc3513-c83a-8b5d-bbff-1a4a0dc001d7\",\n\t\t\"description\": \"version=1.0 - This is a PetStore API description\",\n\t\t\"schema\": \"https://schema.getpostman.com/json/collection/v2.0.0/collection.json\"\n\t},\n\t\"item\": [\n\t\t{\n\t\t\t\"name\": \"pet\",\n\t\t\t\"description\": \"\",\n\t\t\t\"item\": [\n\t\t\t\t{\n\t\t\t\t\t\"name\": \"Finds Pets by status\",\n\t\t\t\t\t\"request\": {\n\t\t\t\t\t\t\"url\": {\n\t\t\t\t\t\t\t\"raw\": \"https://petstore-api-2445581593402.apicast.io:443/v2/pet/findByStatus?user_key=998bac0775b1d5f588e0a6ca7c11b852&status=available\",\n\t\t\t\t\t\t\t\"protocol\": \"https\",\n\t\t\t\t\t\t\t\"host\": [\n\t\t\t\t\t\t\t\t\"petstore-api-2445581593402\",\n\t\t\t\t\t\t\t\t\"apicast\",\n\t\t\t\t\t\t\t\t\"io\"\n\t\t\t\t\t\t\t],\n\t\t\t\t\t\t\t\"port\": \"443\",\n\t\t\t\t\t\t\t\"path\": [\n\t\t\t\t\t\t\t\t\"v2\",\n\t\t\t\t\t\t\t\t\"pet\",\n\t\t\t\t\t\t\t\t\"findByStatus\"\n\t\t\t\t\t\t\t],\n\t\t\t\t\t\t\t\"query\": [\n\t\t\t\t\t\t\t\t{\n\t\t\t\t\t\t\t\t\t\"key\": \"user_key\",\n\t\t\t\t\t\t\t\t\t\"value\": \"998bac0775b1d5f588e0a6ca7c11b852\",\n\t\t\t\t\t\t\t\t\t\"equals\": true,\n\t\t\t\t\t\t\t\t\t\"description\": \"\"\n\t\t\t\t\t\t\t\t},\n\t\t\t\t\t\t\t\t{\n\t\t\t\t\t\t\t\t\t\"key\": \"status\",\n\t\t\t\t\t\t\t\t\t\"value\": \"available\",\n\t\t\t\t\t\t\t\t\t\"equals\": true,\n\t\t\t\t\t\t\t\t\t\"description\": \"\"\n\t\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\t],\n\t\t\t\t\t\t\t\"variable\": []\n\t\t\t\t\t\t},\n\t\t\t\t\t\t\"method\": \"GET\",\n\t\t\t\t\t\t\"header\": [],\n\t\t\t\t\t\t\"body\": {},\n\t\t\t\t\t\t\"description\": \"\"\n\t\t\t\t\t},\n\t\t\t\t\t\"response\": [\n\t\t\t\t\t\t{\n\t\t\t\t\t\t\t\"id\": \"c7e562f0-3d87-4925-96d1-c38e0dc4c0d6\",\n\t\t\t\t\t\t\t\"name\": \"available response\",\n\t\t\t\t\t\t\t\"originalRequest\": {\n\t\t\t\t\t\t\t\t\"url\": {\n\t\t\t\t\t\t\t\t\t\"raw\": \"https://petstore-api-2445581593402.apicast.io:443/v2/pet/findByStatus?user_key=70f735676ec46351c6699c4bb767878a&status=available\",\n\t\t\t\t\t\t\t\t\t\"protocol\": \"https\",\n\t\t\t\t\t\t\t\t\t\"host\": [\n\t\t\t\t\t\t\t\t\t\t\"petstore-api-2445581593402\",\n\t\t\t\t\t\t\t\t\t\t\"apicast\",\n\t\t\t\t\t\t\t\t\t\t\"io\"\n\t\t\t\t\t\t\t\t\t],\n\t\t\t\t\t\t\t\t\t\"port\": \"443\",\n\t\t\t\t\t\t\t\t\t\"path\": [\n\t\t\t\t\t\t\t\t\t\t\"v2\",\n\t\t\t\t\t\t\t\t\t\t\"pet\",\n\t\t\t\t\t\t\t\t\t\t\"findByStatus\"\n\t\t\t\t\t\t\t\t\t],\n\t\t\t\t\t\t\t\t\t\"query\": [\n\t\t\t\t\t\t\t\t\t\t{\n\t\t\t\t\t\t\t\t\t\t\t\"key\": \"user_key\",\n\t\t\t\t\t\t\t\t\t\t\t\"value\": \"70f735676ec46351c6699c4bb767878a\",\n\t\t\t\t\t\t\t\t\t\t\t\"equals\": true,\n\t\t\t\t\t\t\t\t\t\t\t\"description\": \"\"\n\t\t\t\t\t\t\t\t\t\t},\n\t\t\t\t\t\t\t\t\t\t{\n\t\t\t\t\t\t\t\t\t\t\t\"key\": \"status\",\n\t\t\t\t\t\t\t\t\t\t\t\"value\": \"available\",\n\t\t\t\t\t\t\t\t\t\t\t\"equals\": true,\n\t\t\t\t\t\t\t\t\t\t\t\"description\": \"\"\n\t\t\t\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\t\t\t],\n\t\t\t\t\t\t\t\t\t\"variable\": []\n\t\t\t\t\t\t\t\t},\n\t\t\t\t\t\t\t\t\"method\": \"GET\",\n\t\t\t\t\t\t\t\t\"header\": [],\n\t\t\t\t\t\t\t\t\"body\": {}\n\t\t\t\t\t\t\t},\n\t\t\t\t\t\t\t\"status\": \"OK\",\n\t\t\t\t\t\t\t\"code\": 200,\n\t\t\t\t\t\t\t\"_postman_previewlanguage\": \"json\",\n\t\t\t\t\t\t\t\"_postman_previewtype\": \"text\",\n\t\t\t\t\t\t\t\"header\": [\n\t\t\t\t\t\t\t\t{\n\t\t\t\t\t\t\t\t\t\"name\": \"Access-Control-Allow-Headers\",\n\t\t\t\t\t\t\t\t\t\"key\": \"Access-Control-Allow-Headers\",\n\t\t\t\t\t\t\t\t\t\"value\": \"Content-Type, api_key, Authorization\",\n\t\t\t\t\t\t\t\t\t\"description\": \"\"\n\t\t\t\t\t\t\t\t},\n\t\t\t\t\t\t\t\t{\n\t\t\t\t\t\t\t\t\t\"name\": \"Access-Control-Allow-Methods\",\n\t\t\t\t\t\t\t\t\t\"key\": \"Access-Control-Allow-Methods\",\n\t\t\t\t\t\t\t\t\t\"value\": \"GET, POST, DELETE, PUT\",\n\t\t\t\t\t\t\t\t\t\"description\": \"\"\n\t\t\t\t\t\t\t\t},\n\t\t\t\t\t\t\t\t{\n\t\t\t\t\t\t\t\t\t\"name\": \"Access-Control-Allow-Origin\",\n\t\t\t\t\t\t\t\t\t\"key\": \"Access-Control-Allow-Origin\",\n\t\t\t\t\t\t\t\t\t\"value\": \"*\",\n\t\t\t\t\t\t\t\t\t\"description\": \"\"\n\t\t\t\t\t\t\t\t},\n\t\t\t\t\t\t\t\t{\n\t\t\t\t\t\t\t\t\t\"name\": \"Connection\",\n\t\t\t\t\t\t\t\t\t\"key\": \"Connection\",\n\t\t\t\t\t\t\t\t\t\"value\": \"keep-alive\",\n\t\t\t\t\t\t\t\t\t\"description\": \"\"\n\t\t\t\t\t\t\t\t},\n\t\t\t\t\t\t\t\t{\n\t\t\t\t\t\t\t\t\t\"name\": \"Content-Type\",\n\t\t\t\t\t\t\t\t\t\"key\": \"Content-Type\",\n\t\t\t\t\t\t\t\t\t\"value\": \"application/json\",\n\t\t\t\t\t\t\t\t\t\"description\": \"\"\n\t\t\t\t\t\t\t\t},\n\t\t\t\t\t\t\t\t{\n\t\t\t\t\t\t\t\t\t\"name\": \"Date\",\n\t\t\t\t\t\t\t\t\t\"key\": \"Date\",\n\t\t\t\t\t\t\t\t\t\"value\": \"Wed, 07 Dec 2016 15:31:45 GMT\",\n\t\t\t\t\t\t\t\t\t\"description\": \"\"\n\t\t\t\t\t\t\t\t},\n\t\t\t\t\t\t\t\t{\n\t\t\t\t\t\t\t\t\t\"name\": \"Server\",\n\t\t\t\t\t\t\t\t\t\"key\": \"Server\",\n\t\t\t\t\t\t\t\t\t\"value\": \"openresty/1.9.15.1\",\n\t\t\t\t\t\t\t\t\t\"description\": \"\"\n\t\t\t\t\t\t\t\t},\n\t\t\t\t\t\t\t\t{\n\t\t\t\t\t\t\t\t\t\"name\": \"X-Powered-By\",\n\t\t\t\t\t\t\t\t\t\"key\": \"X-Powered-By\",\n\t\t\t\t\t\t\t\t\t\"value\": \"3scale API Management - http://www.3scale.net\",\n\t\t\t\t\t\t\t\t\t\"description\": \"\"\n\t\t\t\t\t\t\t\t},\n\t\t\t\t\t\t\t\t{\n\t\t\t\t\t\t\t\t\t\"name\": \"transfer-encoding\",\n\t\t\t\t\t\t\t\t\t\"key\": \"transfer-encoding\",\n\t\t\t\t\t\t\t\t\t\"value\": \"chunked\",\n\t\t\t\t\t\t\t\t\t\"description\": \"\"\n\t\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\t],\n\t\t\t\t\t\t\t\"cookie\": [],\n\t\t\t\t\t\t\t\"responseTime\": 1466,\n\t\t\t\t\t\t\t\"body\": \"[\\n {\\n \\\"id\\\": 190192062,\\n \\\"category\\\": {\\n \\\"id\\\": 0,\\n \\\"name\\\": \\\"string\\\"\\n },\\n \\\"name\\\": \\\"doggie\\\",\\n \\\"photoUrls\\\": [\\n \\\"string\\\"\\n ],\\n \\\"tags\\\": [\\n {\\n \\\"id\\\": 0,\\n \\\"name\\\": \\\"string\\\"\\n }\\n ],\\n \\\"status\\\": \\\"available\\\"\\n },\\n {\\n \\\"id\\\": 190192063,\\n \\\"category\\\": {\\n \\\"id\\\": 0,\\n \\\"name\\\": \\\"string\\\"\\n },\\n \\\"name\\\": \\\"doggie\\\",\\n \\\"photoUrls\\\": [\\n \\\"string\\\"\\n ],\\n \\\"tags\\\": [\\n {\\n \\\"id\\\": 0,\\n \\\"name\\\": \\\"string\\\"\\n }\\n ],\\n \\\"status\\\": \\\"available\\\"\\n },\\n {\\n \\\"id\\\": 190192285,\\n \\\"category\\\": {\\n \\\"id\\\": 0,\\n \\\"name\\\": \\\"string\\\"\\n },\\n \\\"name\\\": \\\"doggie\\\",\\n \\\"photoUrls\\\": [\\n \\\"string\\\"\\n ],\\n \\\"tags\\\": [\\n {\\n \\\"id\\\": 0,\\n \\\"name\\\": \\\"string\\\"\\n }\\n ],\\n \\\"status\\\": \\\"available\\\"\\n },\\n {\\n \\\"id\\\": 190192654,\\n \\\"category\\\": {\\n \\\"id\\\": 0,\\n \\\"name\\\": \\\"string\\\"\\n },\\n \\\"name\\\": \\\"doggie\\\",\\n \\\"photoUrls\\\": [\\n \\\"string\\\"\\n ],\\n \\\"tags\\\": [\\n {\\n \\\"id\\\": 0,\\n \\\"name\\\": \\\"string\\\"\\n }\\n ],\\n \\\"status\\\": \\\"available\\\"\\n },\\n {\\n \\\"id\\\": 190192671,\\n \\\"category\\\": {\\n \\\"id\\\": 0,\\n \\\"name\\\": \\\"string\\\"\\n },\\n \\\"name\\\": \\\"doggie\\\",\\n \\\"photoUrls\\\": [\\n \\\"string\\\"\\n ],\\n \\\"tags\\\": [\\n {\\n \\\"id\\\": 0,\\n \\\"name\\\": \\\"string\\\"\\n }\\n ],\\n \\\"status\\\": \\\"available\\\"\\n },\\n {\\n \\\"id\\\": 190192727,\\n \\\"category\\\": {\\n \\\"id\\\": 0,\\n \\\"name\\\": \\\"string\\\"\\n },\\n \\\"name\\\": \\\"doggie\\\",\\n \\\"photoUrls\\\": [\\n \\\"string\\\"\\n ],\\n \\\"tags\\\": [\\n {\\n \\\"id\\\": 0,\\n \\\"name\\\": \\\"string\\\"\\n }\\n ],\\n \\\"status\\\": \\\"available\\\"\\n },\\n {\\n \\\"id\\\": 190192736,\\n \\\"category\\\": {\\n \\\"id\\\": 0,\\n \\\"name\\\": \\\"string\\\"\\n },\\n \\\"name\\\": \\\"doggie\\\",\\n \\\"photoUrls\\\": [\\n \\\"string\\\"\\n ],\\n \\\"tags\\\": [\\n {\\n \\\"id\\\": 0,\\n \\\"name\\\": \\\"string\\\"\\n }\\n ],\\n \\\"status\\\": \\\"available\\\"\\n },\\n {\\n \\\"id\\\": 190192768,\\n \\\"category\\\": {\\n \\\"id\\\": 0,\\n \\\"name\\\": \\\"string\\\"\\n },\\n \\\"name\\\": \\\"doggie\\\",\\n \\\"photoUrls\\\": [\\n \\\"string\\\"\\n ],\\n \\\"tags\\\": [\\n {\\n \\\"id\\\": 0,\\n \\\"name\\\": \\\"string\\\"\\n }\\n ],\\n \\\"status\\\": \\\"available\\\"\\n },\\n {\\n \\\"id\\\": 190192878,\\n \\\"category\\\": {\\n \\\"id\\\": 0,\\n \\\"name\\\": \\\"string\\\"\\n },\\n \\\"name\\\": \\\"doggie\\\",\\n \\\"photoUrls\\\": [\\n \\\"string\\\"\\n ],\\n \\\"tags\\\": [\\n {\\n \\\"id\\\": 0,\\n \\\"name\\\": \\\"string\\\"\\n }\\n ],\\n \\\"status\\\": \\\"available\\\"\\n },\\n {\\n \\\"id\\\": 190192907,\\n \\\"category\\\": {\\n \\\"id\\\": 0,\\n \\\"name\\\": \\\"string\\\"\\n },\\n \\\"name\\\": \\\"doggie\\\",\\n \\\"photoUrls\\\": [\\n \\\"string\\\"\\n ],\\n \\\"tags\\\": [\\n {\\n \\\"id\\\": 0,\\n \\\"name\\\": \\\"string\\\"\\n }\\n ],\\n \\\"status\\\": \\\"available\\\"\\n },\\n {\\n \\\"id\\\": 190193000,\\n \\\"category\\\": {\\n \\\"id\\\": 0,\\n \\\"name\\\": \\\"string\\\"\\n },\\n \\\"name\\\": \\\"doggie\\\",\\n \\\"photoUrls\\\": [\\n \\\"string\\\"\\n ],\\n \\\"tags\\\": [\\n {\\n \\\"id\\\": 0,\\n \\\"name\\\": \\\"string\\\"\\n }\\n ],\\n \\\"status\\\": \\\"available\\\"\\n },\\n {\\n \\\"id\\\": -98125093,\\n \\\"category\\\": {\\n \\\"id\\\": -517488397,\\n \\\"name\\\": \\\"EJvNbK\\\"\\n },\\n \\\"name\\\": \\\"LuEfMZATrHz\\\",\\n \\\"photoUrls\\\": [\\n \\\"XCXOVVkaxa\\\",\\n \\\"gNwYqHEmC\\\",\\n \\\"nvCvphDeuqztysUBNed\\\",\\n \\\"W\\\",\\n \\\"vmrxRIViyXqumolLIeoB\\\",\\n \\\"JRqHVxk\\\",\\n \\\"tCUGbegVHoXajm\\\",\\n \\\"UiHppQn\\\"\\n ],\\n \\\"tags\\\": [\\n {\\n \\\"id\\\": 727599428,\\n \\\"name\\\": \\\"RemggEDzxPljbrlktdWf\\\"\\n },\\n {\\n \\\"id\\\": 1987753751,\\n \\\"name\\\": \\\"zWqdKAGHMmhPPlomljaNtuvm\\\"\\n },\\n {\\n \\\"id\\\": 1251632392,\\n \\\"name\\\": \\\"BAgtgtKOxZGdsS\\\"\\n },\\n {\\n \\\"id\\\": -1813025208,\\n \\\"name\\\": \\\"OkKxtfAkCMEICbbQDVPi\\\"\\n },\\n {\\n \\\"id\\\": -730110346,\\n \\\"name\\\": \\\"WshDF\\\"\\n },\\n {\\n \\\"id\\\": 2100951153,\\n \\\"name\\\": \\\"yxUFSknQEleIAQCoocl\\\"\\n },\\n {\\n \\\"id\\\": -2135188117,\\n \\\"name\\\": \\\"M\\\"\\n },\\n {\\n \\\"id\\\": 1352243140,\\n \\\"name\\\": \\\"koKHsjysHXW\\\"\\n },\\n {\\n \\\"id\\\": 1696778814,\\n \\\"name\\\": \\\"KaihiyarcZkIzkkquWPZ\\\"\\n },\\n {\\n \\\"id\\\": 659492963,\\n \\\"name\\\": \\\"xqIzulcBPzWMyUpQwQK\\\"\\n },\\n {\\n \\\"id\\\": -2118372841,\\n \\\"name\\\": \\\"naYFGuHmqDqOpfHH\\\"\\n }\\n ],\\n \\\"status\\\": \\\"available\\\"\\n }\\n]\"\n\t\t\t\t\t\t}\n\t\t\t\t\t]\n\t\t\t\t},\n\t\t\t\t{\n\t\t\t\t\t\"name\": \"Find pet by ID\",\n\t\t\t\t\t\"request\": {\n\t\t\t\t\t\t\"url\": {\n\t\t\t\t\t\t\t\"raw\": \"https://petstore-api-2445581593402.apicast.io:443/v2/pet/:petId?user_key={{user_key}}\",\n\t\t\t\t\t\t\t\"protocol\": \"https\",\n\t\t\t\t\t\t\t\"host\": [\n\t\t\t\t\t\t\t\t\"petstore-api-2445581593402\",\n\t\t\t\t\t\t\t\t\"apicast\",\n\t\t\t\t\t\t\t\t\"io\"\n\t\t\t\t\t\t\t],\n\t\t\t\t\t\t\t\"port\": \"443\",\n\t\t\t\t\t\t\t\"path\": [\n\t\t\t\t\t\t\t\t\"v2\",\n\t\t\t\t\t\t\t\t\"pet\",\n\t\t\t\t\t\t\t\t\":petId\"\n\t\t\t\t\t\t\t],\n\t\t\t\t\t\t\t\"query\": [\n\t\t\t\t\t\t\t\t{\n\t\t\t\t\t\t\t\t\t\"key\": \"user_key\",\n\t\t\t\t\t\t\t\t\t\"value\": \"{{user_key}}\",\n\t\t\t\t\t\t\t\t\t\"equals\": true,\n\t\t\t\t\t\t\t\t\t\"description\": \"\"\n\t\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\t],\n\t\t\t\t\t\t\t\"variable\": [\n\t\t\t\t\t\t\t\t{\n\t\t\t\t\t\t\t\t\t\"key\": \"petId\",\n\t\t\t\t\t\t\t\t\t\"value\": \"\"\n\t\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\t]\n\t\t\t\t\t\t},\n\t\t\t\t\t\t\"method\": \"GET\",\n\t\t\t\t\t\t\"header\": [],\n\t\t\t\t\t\t\"body\": {},\n\t\t\t\t\t\t\"description\": \"\"\n\t\t\t\t\t},\n\t\t\t\t\t\"response\": [\n\t\t\t\t\t\t{\n\t\t\t\t\t\t\t\"id\": \"05486047-439f-408d-97e7-a9925107a2a1\",\n\t\t\t\t\t\t\t\"name\": \"get-2\",\n\t\t\t\t\t\t\t\"originalRequest\": {\n\t\t\t\t\t\t\t\t\"url\": {\n\t\t\t\t\t\t\t\t\t\"raw\": \"https://petstore-api-2445581593402.staging.apicast.io:443/v2/pet/:petId?user_key=70f735676ec46351c6699c4bb767878a\",\n\t\t\t\t\t\t\t\t\t\"protocol\": \"https\",\n\t\t\t\t\t\t\t\t\t\"host\": [\n\t\t\t\t\t\t\t\t\t\t\"petstore-api-2445581593402\",\n\t\t\t\t\t\t\t\t\t\t\"staging\",\n\t\t\t\t\t\t\t\t\t\t\"apicast\",\n\t\t\t\t\t\t\t\t\t\t\"io\"\n\t\t\t\t\t\t\t\t\t],\n\t\t\t\t\t\t\t\t\t\"port\": \"443\",\n\t\t\t\t\t\t\t\t\t\"path\": [\n\t\t\t\t\t\t\t\t\t\t\"v2\",\n\t\t\t\t\t\t\t\t\t\t\"pet\",\n\t\t\t\t\t\t\t\t\t\t\":petId\",\n\t\t\t\t\t\t\t\t\t\t\"\"\n\t\t\t\t\t\t\t\t\t],\n\t\t\t\t\t\t\t\t\t\"query\": [\n\t\t\t\t\t\t\t\t\t\t{\n\t\t\t\t\t\t\t\t\t\t\t\"key\": \"user_key\",\n\t\t\t\t\t\t\t\t\t\t\t\"value\": \"70f735676ec46351c6699c4bb767878a\",\n\t\t\t\t\t\t\t\t\t\t\t\"equals\": true,\n\t\t\t\t\t\t\t\t\t\t\t\"description\": \"\"\n\t\t\t\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\t\t\t],\n\t\t\t\t\t\t\t\t\t\"variable\": [\n\t\t\t\t\t\t\t\t\t\t{\n\t\t\t\t\t\t\t\t\t\t\t\"key\": \"petId\",\n\t\t\t\t\t\t\t\t\t\t\t\"value\": \"2\"\n\t\t\t\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\t\t\t]\n\t\t\t\t\t\t\t\t},\n\t\t\t\t\t\t\t\t\"method\": \"GET\",\n\t\t\t\t\t\t\t\t\"header\": [],\n\t\t\t\t\t\t\t\t\"body\": {}\n\t\t\t\t\t\t\t},\n\t\t\t\t\t\t\t\"status\": \"OK\",\n\t\t\t\t\t\t\t\"code\": 200,\n\t\t\t\t\t\t\t\"_postman_previewlanguage\": \"json\",\n\t\t\t\t\t\t\t\"_postman_previewtype\": \"text\",\n\t\t\t\t\t\t\t\"header\": [\n\t\t\t\t\t\t\t\t{\n\t\t\t\t\t\t\t\t\t\"name\": \"Access-Control-Allow-Headers\",\n\t\t\t\t\t\t\t\t\t\"key\": \"Access-Control-Allow-Headers\",\n\t\t\t\t\t\t\t\t\t\"value\": \"Content-Type, api_key, Authorization\",\n\t\t\t\t\t\t\t\t\t\"description\": \"\"\n\t\t\t\t\t\t\t\t},\n\t\t\t\t\t\t\t\t{\n\t\t\t\t\t\t\t\t\t\"name\": \"Access-Control-Allow-Methods\",\n\t\t\t\t\t\t\t\t\t\"key\": \"Access-Control-Allow-Methods\",\n\t\t\t\t\t\t\t\t\t\"value\": \"GET, POST, DELETE, PUT\",\n\t\t\t\t\t\t\t\t\t\"description\": \"\"\n\t\t\t\t\t\t\t\t},\n\t\t\t\t\t\t\t\t{\n\t\t\t\t\t\t\t\t\t\"name\": \"Access-Control-Allow-Origin\",\n\t\t\t\t\t\t\t\t\t\"key\": \"Access-Control-Allow-Origin\",\n\t\t\t\t\t\t\t\t\t\"value\": \"*\",\n\t\t\t\t\t\t\t\t\t\"description\": \"\"\n\t\t\t\t\t\t\t\t},\n\t\t\t\t\t\t\t\t{\n\t\t\t\t\t\t\t\t\t\"name\": \"Connection\",\n\t\t\t\t\t\t\t\t\t\"key\": \"Connection\",\n\t\t\t\t\t\t\t\t\t\"value\": \"keep-alive\",\n\t\t\t\t\t\t\t\t\t\"description\": \"\"\n\t\t\t\t\t\t\t\t},\n\t\t\t\t\t\t\t\t{\n\t\t\t\t\t\t\t\t\t\"name\": \"Content-Length\",\n\t\t\t\t\t\t\t\t\t\"key\": \"Content-Length\",\n\t\t\t\t\t\t\t\t\t\"value\": \"137\",\n\t\t\t\t\t\t\t\t\t\"description\": \"\"\n\t\t\t\t\t\t\t\t},\n\t\t\t\t\t\t\t\t{\n\t\t\t\t\t\t\t\t\t\"name\": \"Content-Type\",\n\t\t\t\t\t\t\t\t\t\"key\": \"Content-Type\",\n\t\t\t\t\t\t\t\t\t\"value\": \"application/json\",\n\t\t\t\t\t\t\t\t\t\"description\": \"\"\n\t\t\t\t\t\t\t\t},\n\t\t\t\t\t\t\t\t{\n\t\t\t\t\t\t\t\t\t\"name\": \"Date\",\n\t\t\t\t\t\t\t\t\t\"key\": \"Date\",\n\t\t\t\t\t\t\t\t\t\"value\": \"Wed, 07 Dec 2016 15:27:18 GMT\",\n\t\t\t\t\t\t\t\t\t\"description\": \"\"\n\t\t\t\t\t\t\t\t},\n\t\t\t\t\t\t\t\t{\n\t\t\t\t\t\t\t\t\t\"name\": \"Server\",\n\t\t\t\t\t\t\t\t\t\"key\": \"Server\",\n\t\t\t\t\t\t\t\t\t\"value\": \"openresty/1.9.7.4\",\n\t\t\t\t\t\t\t\t\t\"description\": \"\"\n\t\t\t\t\t\t\t\t},\n\t\t\t\t\t\t\t\t{\n\t\t\t\t\t\t\t\t\t\"name\": \"X-Powered-By\",\n\t\t\t\t\t\t\t\t\t\"key\": \"X-Powered-By\",\n\t\t\t\t\t\t\t\t\t\"value\": \"3scale API Management - http://www.3scale.net\",\n\t\t\t\t\t\t\t\t\t\"description\": \"\"\n\t\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\t],\n\t\t\t\t\t\t\t\"cookie\": [],\n\t\t\t\t\t\t\t\"responseTime\": 233,\n\t\t\t\t\t\t\t\"body\": \"{\\\"id\\\":2,\\\"category\\\":{\\\"id\\\":1,\\\"name\\\":\\\"Animal\\\"},\\\"name\\\":\\\"cat\\\",\\\"photoUrls\\\":[\\\"string\\\"],\\\"tags\\\":[{\\\"id\\\":1,\\\"name\\\":\\\"domestic\\\"}],\\\"status\\\":\\\"available\\\"}\"\n\t\t\t\t\t\t},\n\t\t\t\t\t\t{\n\t\t\t\t\t\t\t\"id\": \"187fb73f-edbb-47d4-89ae-7e3e4a8cfcbd\",\n\t\t\t\t\t\t\t\"name\": \"get-1\",\n\t\t\t\t\t\t\t\"originalRequest\": {\n\t\t\t\t\t\t\t\t\"url\": {\n\t\t\t\t\t\t\t\t\t\"raw\": \"https://petstore-api-2445581593402.apicast.io:443/v2/pet/:petId?user_key=998bac0775b1d5f588e0a6ca7c11b852\",\n\t\t\t\t\t\t\t\t\t\"protocol\": \"https\",\n\t\t\t\t\t\t\t\t\t\"host\": [\n\t\t\t\t\t\t\t\t\t\t\"petstore-api-2445581593402\",\n\t\t\t\t\t\t\t\t\t\t\"apicast\",\n\t\t\t\t\t\t\t\t\t\t\"io\"\n\t\t\t\t\t\t\t\t\t],\n\t\t\t\t\t\t\t\t\t\"port\": \"443\",\n\t\t\t\t\t\t\t\t\t\"path\": [\n\t\t\t\t\t\t\t\t\t\t\"v2\",\n\t\t\t\t\t\t\t\t\t\t\"pet\",\n\t\t\t\t\t\t\t\t\t\t\":petId\"\n\t\t\t\t\t\t\t\t\t],\n\t\t\t\t\t\t\t\t\t\"query\": [\n\t\t\t\t\t\t\t\t\t\t{\n\t\t\t\t\t\t\t\t\t\t\t\"key\": \"user_key\",\n\t\t\t\t\t\t\t\t\t\t\t\"value\": \"998bac0775b1d5f588e0a6ca7c11b852\",\n\t\t\t\t\t\t\t\t\t\t\t\"equals\": true,\n\t\t\t\t\t\t\t\t\t\t\t\"description\": \"\"\n\t\t\t\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\t\t\t],\n\t\t\t\t\t\t\t\t\t\"variable\": [\n\t\t\t\t\t\t\t\t\t\t{\n\t\t\t\t\t\t\t\t\t\t\t\"key\": \"petId\",\n\t\t\t\t\t\t\t\t\t\t\t\"value\": \"1\"\n\t\t\t\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\t\t\t]\n\t\t\t\t\t\t\t\t},\n\t\t\t\t\t\t\t\t\"method\": \"GET\",\n\t\t\t\t\t\t\t\t\"header\": [],\n\t\t\t\t\t\t\t\t\"body\": {}\n\t\t\t\t\t\t\t},\n\t\t\t\t\t\t\t\"status\": \"Not Found\",\n\t\t\t\t\t\t\t\"code\": 404,\n\t\t\t\t\t\t\t\"_postman_previewlanguage\": \"\",\n\t\t\t\t\t\t\t\"_postman_previewtype\": \"parsed\",\n\t\t\t\t\t\t\t\"header\": [\n\t\t\t\t\t\t\t\t{\n\t\t\t\t\t\t\t\t\t\"key\": \"Access-Control-Allow-Headers\",\n\t\t\t\t\t\t\t\t\t\"value\": \"Content-Type, api_key, Authorization\",\n\t\t\t\t\t\t\t\t\t\"description\": \"\",\n\t\t\t\t\t\t\t\t\t\"type\": \"text\",\n\t\t\t\t\t\t\t\t\t\"name\": \"Access-Control-Allow-Headers\"\n\t\t\t\t\t\t\t\t},\n\t\t\t\t\t\t\t\t{\n\t\t\t\t\t\t\t\t\t\"key\": \"Access-Control-Allow-Methods\",\n\t\t\t\t\t\t\t\t\t\"value\": \"GET, POST, DELETE, PUT\",\n\t\t\t\t\t\t\t\t\t\"description\": \"\",\n\t\t\t\t\t\t\t\t\t\"type\": \"text\",\n\t\t\t\t\t\t\t\t\t\"name\": \"Access-Control-Allow-Methods\"\n\t\t\t\t\t\t\t\t},\n\t\t\t\t\t\t\t\t{\n\t\t\t\t\t\t\t\t\t\"key\": \"Access-Control-Allow-Origin\",\n\t\t\t\t\t\t\t\t\t\"value\": \"*\",\n\t\t\t\t\t\t\t\t\t\"description\": \"\",\n\t\t\t\t\t\t\t\t\t\"type\": \"text\",\n\t\t\t\t\t\t\t\t\t\"name\": \"Access-Control-Allow-Origin\"\n\t\t\t\t\t\t\t\t},\n\t\t\t\t\t\t\t\t{\n\t\t\t\t\t\t\t\t\t\"key\": \"Content-Type\",\n\t\t\t\t\t\t\t\t\t\"value\": \"application/json\",\n\t\t\t\t\t\t\t\t\t\"name\": \"Content-Type\",\n\t\t\t\t\t\t\t\t\t\"description\": \"\"\n\t\t\t\t\t\t\t\t},\n\t\t\t\t\t\t\t\t{\n\t\t\t\t\t\t\t\t\t\"key\": \"Content-Length\",\n\t\t\t\t\t\t\t\t\t\"value\": \"0\",\n\t\t\t\t\t\t\t\t\t\"description\": \"\",\n\t\t\t\t\t\t\t\t\t\"type\": \"text\",\n\t\t\t\t\t\t\t\t\t\"name\": \"Content-Length\"\n\t\t\t\t\t\t\t\t},\n\t\t\t\t\t\t\t\t{\n\t\t\t\t\t\t\t\t\t\"key\": \"Server\",\n\t\t\t\t\t\t\t\t\t\"value\": \"openresty/1.9.7.4\",\n\t\t\t\t\t\t\t\t\t\"description\": \"\",\n\t\t\t\t\t\t\t\t\t\"type\": \"text\",\n\t\t\t\t\t\t\t\t\t\"name\": \"Server\"\n\t\t\t\t\t\t\t\t},\n\t\t\t\t\t\t\t\t{\n\t\t\t\t\t\t\t\t\t\"key\": \"Date\",\n\t\t\t\t\t\t\t\t\t\"value\": \"Wed, 07 Dec 2016 15:27:22 GMT\",\n\t\t\t\t\t\t\t\t\t\"description\": \"\",\n\t\t\t\t\t\t\t\t\t\"type\": \"text\",\n\t\t\t\t\t\t\t\t\t\"name\": \"Date\"\n\t\t\t\t\t\t\t\t},\n\t\t\t\t\t\t\t\t{\n\t\t\t\t\t\t\t\t\t\"key\": \"X-Powered-By\",\n\t\t\t\t\t\t\t\t\t\"value\": \"3scale API Management - http://www.3scale.net\",\n\t\t\t\t\t\t\t\t\t\"description\": \"\",\n\t\t\t\t\t\t\t\t\t\"type\": \"text\",\n\t\t\t\t\t\t\t\t\t\"name\": \"X-Powered-By\"\n\t\t\t\t\t\t\t\t},\n\t\t\t\t\t\t\t\t{\n\t\t\t\t\t\t\t\t\t\"key\": \"Connection\",\n\t\t\t\t\t\t\t\t\t\"value\": \"keep-alive\",\n\t\t\t\t\t\t\t\t\t\"description\": \"\",\n\t\t\t\t\t\t\t\t\t\"type\": \"text\",\n\t\t\t\t\t\t\t\t\t\"name\": \"Connection\"\n\t\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\t],\n\t\t\t\t\t\t\t\"cookie\": [],\n\t\t\t\t\t\t\t\"responseTime\": 0,\n\t\t\t\t\t\t\t\"body\": \"\"\n\t\t\t\t\t\t}\n\t\t\t\t\t]\n\t\t\t\t}\n\t\t\t]\n\t\t}\n\t]\n}\n", + "type": "POSTMAN_COLLECTION", + "serviceId": "64b99e83e2dbae25009ded78", + "sourceArtifact": "https://raw.githubusercontent.com/microcks/microcks/master/samples/PetstoreAPI-collection.json", + "operations": null + }, + { + "id": "6538d4aab525f9597c9de2f3", + "name": "Petstore API-1.0.json", + "path": null, + "content": "{\n\t\"variables\": [],\n\t\"info\": {\n\t\t\"name\": \"Petstore API\",\n\t\t\"_postman_id\": \"c0bc3513-c83a-8b5d-bbff-1a4a0dc001d7\",\n\t\t\"description\": \"version=1.0 - This is a PetStore API description\",\n\t\t\"schema\": \"https://schema.getpostman.com/json/collection/v2.0.0/collection.json\"\n\t},\n\t\"item\": [\n\t\t{\n\t\t\t\"name\": \"pet\",\n\t\t\t\"description\": \"\",\n\t\t\t\"item\": [\n\t\t\t\t{\n\t\t\t\t\t\"name\": \"Finds Pets by status\",\n\t\t\t\t\t\"request\": {\n\t\t\t\t\t\t\"url\": {\n\t\t\t\t\t\t\t\"raw\": \"https://petstore-api-2445581593402.apicast.io:443/v2/pet/findByStatus?user_key=998bac0775b1d5f588e0a6ca7c11b852&status=available\",\n\t\t\t\t\t\t\t\"protocol\": \"https\",\n\t\t\t\t\t\t\t\"host\": [\n\t\t\t\t\t\t\t\t\"petstore-api-2445581593402\",\n\t\t\t\t\t\t\t\t\"apicast\",\n\t\t\t\t\t\t\t\t\"io\"\n\t\t\t\t\t\t\t],\n\t\t\t\t\t\t\t\"port\": \"443\",\n\t\t\t\t\t\t\t\"path\": [\n\t\t\t\t\t\t\t\t\"v2\",\n\t\t\t\t\t\t\t\t\"pet\",\n\t\t\t\t\t\t\t\t\"findByStatus\"\n\t\t\t\t\t\t\t],\n\t\t\t\t\t\t\t\"query\": [\n\t\t\t\t\t\t\t\t{\n\t\t\t\t\t\t\t\t\t\"key\": \"user_key\",\n\t\t\t\t\t\t\t\t\t\"value\": \"998bac0775b1d5f588e0a6ca7c11b852\",\n\t\t\t\t\t\t\t\t\t\"equals\": true,\n\t\t\t\t\t\t\t\t\t\"description\": \"\"\n\t\t\t\t\t\t\t\t},\n\t\t\t\t\t\t\t\t{\n\t\t\t\t\t\t\t\t\t\"key\": \"status\",\n\t\t\t\t\t\t\t\t\t\"value\": \"available\",\n\t\t\t\t\t\t\t\t\t\"equals\": true,\n\t\t\t\t\t\t\t\t\t\"description\": \"\"\n\t\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\t],\n\t\t\t\t\t\t\t\"variable\": []\n\t\t\t\t\t\t},\n\t\t\t\t\t\t\"method\": \"GET\",\n\t\t\t\t\t\t\"header\": [],\n\t\t\t\t\t\t\"body\": {},\n\t\t\t\t\t\t\"description\": \"\"\n\t\t\t\t\t},\n\t\t\t\t\t\"response\": [\n\t\t\t\t\t\t{\n\t\t\t\t\t\t\t\"id\": \"c7e562f0-3d87-4925-96d1-c38e0dc4c0d6\",\n\t\t\t\t\t\t\t\"name\": \"available response\",\n\t\t\t\t\t\t\t\"originalRequest\": {\n\t\t\t\t\t\t\t\t\"url\": {\n\t\t\t\t\t\t\t\t\t\"raw\": \"https://petstore-api-2445581593402.apicast.io:443/v2/pet/findByStatus?user_key=70f735676ec46351c6699c4bb767878a&status=available\",\n\t\t\t\t\t\t\t\t\t\"protocol\": \"https\",\n\t\t\t\t\t\t\t\t\t\"host\": [\n\t\t\t\t\t\t\t\t\t\t\"petstore-api-2445581593402\",\n\t\t\t\t\t\t\t\t\t\t\"apicast\",\n\t\t\t\t\t\t\t\t\t\t\"io\"\n\t\t\t\t\t\t\t\t\t],\n\t\t\t\t\t\t\t\t\t\"port\": \"443\",\n\t\t\t\t\t\t\t\t\t\"path\": [\n\t\t\t\t\t\t\t\t\t\t\"v2\",\n\t\t\t\t\t\t\t\t\t\t\"pet\",\n\t\t\t\t\t\t\t\t\t\t\"findByStatus\"\n\t\t\t\t\t\t\t\t\t],\n\t\t\t\t\t\t\t\t\t\"query\": [\n\t\t\t\t\t\t\t\t\t\t{\n\t\t\t\t\t\t\t\t\t\t\t\"key\": \"user_key\",\n\t\t\t\t\t\t\t\t\t\t\t\"value\": \"70f735676ec46351c6699c4bb767878a\",\n\t\t\t\t\t\t\t\t\t\t\t\"equals\": true,\n\t\t\t\t\t\t\t\t\t\t\t\"description\": \"\"\n\t\t\t\t\t\t\t\t\t\t},\n\t\t\t\t\t\t\t\t\t\t{\n\t\t\t\t\t\t\t\t\t\t\t\"key\": \"status\",\n\t\t\t\t\t\t\t\t\t\t\t\"value\": \"available\",\n\t\t\t\t\t\t\t\t\t\t\t\"equals\": true,\n\t\t\t\t\t\t\t\t\t\t\t\"description\": \"\"\n\t\t\t\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\t\t\t],\n\t\t\t\t\t\t\t\t\t\"variable\": []\n\t\t\t\t\t\t\t\t},\n\t\t\t\t\t\t\t\t\"method\": \"GET\",\n\t\t\t\t\t\t\t\t\"header\": [],\n\t\t\t\t\t\t\t\t\"body\": {}\n\t\t\t\t\t\t\t},\n\t\t\t\t\t\t\t\"status\": \"OK\",\n\t\t\t\t\t\t\t\"code\": 200,\n\t\t\t\t\t\t\t\"_postman_previewlanguage\": \"json\",\n\t\t\t\t\t\t\t\"_postman_previewtype\": \"text\",\n\t\t\t\t\t\t\t\"header\": [\n\t\t\t\t\t\t\t\t{\n\t\t\t\t\t\t\t\t\t\"name\": \"Access-Control-Allow-Headers\",\n\t\t\t\t\t\t\t\t\t\"key\": \"Access-Control-Allow-Headers\",\n\t\t\t\t\t\t\t\t\t\"value\": \"Content-Type, api_key, Authorization\",\n\t\t\t\t\t\t\t\t\t\"description\": \"\"\n\t\t\t\t\t\t\t\t},\n\t\t\t\t\t\t\t\t{\n\t\t\t\t\t\t\t\t\t\"name\": \"Access-Control-Allow-Methods\",\n\t\t\t\t\t\t\t\t\t\"key\": \"Access-Control-Allow-Methods\",\n\t\t\t\t\t\t\t\t\t\"value\": \"GET, POST, DELETE, PUT\",\n\t\t\t\t\t\t\t\t\t\"description\": \"\"\n\t\t\t\t\t\t\t\t},\n\t\t\t\t\t\t\t\t{\n\t\t\t\t\t\t\t\t\t\"name\": \"Access-Control-Allow-Origin\",\n\t\t\t\t\t\t\t\t\t\"key\": \"Access-Control-Allow-Origin\",\n\t\t\t\t\t\t\t\t\t\"value\": \"*\",\n\t\t\t\t\t\t\t\t\t\"description\": \"\"\n\t\t\t\t\t\t\t\t},\n\t\t\t\t\t\t\t\t{\n\t\t\t\t\t\t\t\t\t\"name\": \"Connection\",\n\t\t\t\t\t\t\t\t\t\"key\": \"Connection\",\n\t\t\t\t\t\t\t\t\t\"value\": \"keep-alive\",\n\t\t\t\t\t\t\t\t\t\"description\": \"\"\n\t\t\t\t\t\t\t\t},\n\t\t\t\t\t\t\t\t{\n\t\t\t\t\t\t\t\t\t\"name\": \"Content-Type\",\n\t\t\t\t\t\t\t\t\t\"key\": \"Content-Type\",\n\t\t\t\t\t\t\t\t\t\"value\": \"application/json\",\n\t\t\t\t\t\t\t\t\t\"description\": \"\"\n\t\t\t\t\t\t\t\t},\n\t\t\t\t\t\t\t\t{\n\t\t\t\t\t\t\t\t\t\"name\": \"Date\",\n\t\t\t\t\t\t\t\t\t\"key\": \"Date\",\n\t\t\t\t\t\t\t\t\t\"value\": \"Wed, 07 Dec 2016 15:31:45 GMT\",\n\t\t\t\t\t\t\t\t\t\"description\": \"\"\n\t\t\t\t\t\t\t\t},\n\t\t\t\t\t\t\t\t{\n\t\t\t\t\t\t\t\t\t\"name\": \"Server\",\n\t\t\t\t\t\t\t\t\t\"key\": \"Server\",\n\t\t\t\t\t\t\t\t\t\"value\": \"openresty/1.9.15.1\",\n\t\t\t\t\t\t\t\t\t\"description\": \"\"\n\t\t\t\t\t\t\t\t},\n\t\t\t\t\t\t\t\t{\n\t\t\t\t\t\t\t\t\t\"name\": \"X-Powered-By\",\n\t\t\t\t\t\t\t\t\t\"key\": \"X-Powered-By\",\n\t\t\t\t\t\t\t\t\t\"value\": \"3scale API Management - http://www.3scale.net\",\n\t\t\t\t\t\t\t\t\t\"description\": \"\"\n\t\t\t\t\t\t\t\t},\n\t\t\t\t\t\t\t\t{\n\t\t\t\t\t\t\t\t\t\"name\": \"transfer-encoding\",\n\t\t\t\t\t\t\t\t\t\"key\": \"transfer-encoding\",\n\t\t\t\t\t\t\t\t\t\"value\": \"chunked\",\n\t\t\t\t\t\t\t\t\t\"description\": \"\"\n\t\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\t],\n\t\t\t\t\t\t\t\"cookie\": [],\n\t\t\t\t\t\t\t\"responseTime\": 1466,\n\t\t\t\t\t\t\t\"body\": \"[\\n {\\n \\\"id\\\": 190192062,\\n \\\"category\\\": {\\n \\\"id\\\": 0,\\n \\\"name\\\": \\\"string\\\"\\n },\\n \\\"name\\\": \\\"doggie\\\",\\n \\\"photoUrls\\\": [\\n \\\"string\\\"\\n ],\\n \\\"tags\\\": [\\n {\\n \\\"id\\\": 0,\\n \\\"name\\\": \\\"string\\\"\\n }\\n ],\\n \\\"status\\\": \\\"available\\\"\\n },\\n {\\n \\\"id\\\": 190192063,\\n \\\"category\\\": {\\n \\\"id\\\": 0,\\n \\\"name\\\": \\\"string\\\"\\n },\\n \\\"name\\\": \\\"doggie\\\",\\n \\\"photoUrls\\\": [\\n \\\"string\\\"\\n ],\\n \\\"tags\\\": [\\n {\\n \\\"id\\\": 0,\\n \\\"name\\\": \\\"string\\\"\\n }\\n ],\\n \\\"status\\\": \\\"available\\\"\\n },\\n {\\n \\\"id\\\": 190192285,\\n \\\"category\\\": {\\n \\\"id\\\": 0,\\n \\\"name\\\": \\\"string\\\"\\n },\\n \\\"name\\\": \\\"doggie\\\",\\n \\\"photoUrls\\\": [\\n \\\"string\\\"\\n ],\\n \\\"tags\\\": [\\n {\\n \\\"id\\\": 0,\\n \\\"name\\\": \\\"string\\\"\\n }\\n ],\\n \\\"status\\\": \\\"available\\\"\\n },\\n {\\n \\\"id\\\": 190192654,\\n \\\"category\\\": {\\n \\\"id\\\": 0,\\n \\\"name\\\": \\\"string\\\"\\n },\\n \\\"name\\\": \\\"doggie\\\",\\n \\\"photoUrls\\\": [\\n \\\"string\\\"\\n ],\\n \\\"tags\\\": [\\n {\\n \\\"id\\\": 0,\\n \\\"name\\\": \\\"string\\\"\\n }\\n ],\\n \\\"status\\\": \\\"available\\\"\\n },\\n {\\n \\\"id\\\": 190192671,\\n \\\"category\\\": {\\n \\\"id\\\": 0,\\n \\\"name\\\": \\\"string\\\"\\n },\\n \\\"name\\\": \\\"doggie\\\",\\n \\\"photoUrls\\\": [\\n \\\"string\\\"\\n ],\\n \\\"tags\\\": [\\n {\\n \\\"id\\\": 0,\\n \\\"name\\\": \\\"string\\\"\\n }\\n ],\\n \\\"status\\\": \\\"available\\\"\\n },\\n {\\n \\\"id\\\": 190192727,\\n \\\"category\\\": {\\n \\\"id\\\": 0,\\n \\\"name\\\": \\\"string\\\"\\n },\\n \\\"name\\\": \\\"doggie\\\",\\n \\\"photoUrls\\\": [\\n \\\"string\\\"\\n ],\\n \\\"tags\\\": [\\n {\\n \\\"id\\\": 0,\\n \\\"name\\\": \\\"string\\\"\\n }\\n ],\\n \\\"status\\\": \\\"available\\\"\\n },\\n {\\n \\\"id\\\": 190192736,\\n \\\"category\\\": {\\n \\\"id\\\": 0,\\n \\\"name\\\": \\\"string\\\"\\n },\\n \\\"name\\\": \\\"doggie\\\",\\n \\\"photoUrls\\\": [\\n \\\"string\\\"\\n ],\\n \\\"tags\\\": [\\n {\\n \\\"id\\\": 0,\\n \\\"name\\\": \\\"string\\\"\\n }\\n ],\\n \\\"status\\\": \\\"available\\\"\\n },\\n {\\n \\\"id\\\": 190192768,\\n \\\"category\\\": {\\n \\\"id\\\": 0,\\n \\\"name\\\": \\\"string\\\"\\n },\\n \\\"name\\\": \\\"doggie\\\",\\n \\\"photoUrls\\\": [\\n \\\"string\\\"\\n ],\\n \\\"tags\\\": [\\n {\\n \\\"id\\\": 0,\\n \\\"name\\\": \\\"string\\\"\\n }\\n ],\\n \\\"status\\\": \\\"available\\\"\\n },\\n {\\n \\\"id\\\": 190192878,\\n \\\"category\\\": {\\n \\\"id\\\": 0,\\n \\\"name\\\": \\\"string\\\"\\n },\\n \\\"name\\\": \\\"doggie\\\",\\n \\\"photoUrls\\\": [\\n \\\"string\\\"\\n ],\\n \\\"tags\\\": [\\n {\\n \\\"id\\\": 0,\\n \\\"name\\\": \\\"string\\\"\\n }\\n ],\\n \\\"status\\\": \\\"available\\\"\\n },\\n {\\n \\\"id\\\": 190192907,\\n \\\"category\\\": {\\n \\\"id\\\": 0,\\n \\\"name\\\": \\\"string\\\"\\n },\\n \\\"name\\\": \\\"doggie\\\",\\n \\\"photoUrls\\\": [\\n \\\"string\\\"\\n ],\\n \\\"tags\\\": [\\n {\\n \\\"id\\\": 0,\\n \\\"name\\\": \\\"string\\\"\\n }\\n ],\\n \\\"status\\\": \\\"available\\\"\\n },\\n {\\n \\\"id\\\": 190193000,\\n \\\"category\\\": {\\n \\\"id\\\": 0,\\n \\\"name\\\": \\\"string\\\"\\n },\\n \\\"name\\\": \\\"doggie\\\",\\n \\\"photoUrls\\\": [\\n \\\"string\\\"\\n ],\\n \\\"tags\\\": [\\n {\\n \\\"id\\\": 0,\\n \\\"name\\\": \\\"string\\\"\\n }\\n ],\\n \\\"status\\\": \\\"available\\\"\\n },\\n {\\n \\\"id\\\": -98125093,\\n \\\"category\\\": {\\n \\\"id\\\": -517488397,\\n \\\"name\\\": \\\"EJvNbK\\\"\\n },\\n \\\"name\\\": \\\"LuEfMZATrHz\\\",\\n \\\"photoUrls\\\": [\\n \\\"XCXOVVkaxa\\\",\\n \\\"gNwYqHEmC\\\",\\n \\\"nvCvphDeuqztysUBNed\\\",\\n \\\"W\\\",\\n \\\"vmrxRIViyXqumolLIeoB\\\",\\n \\\"JRqHVxk\\\",\\n \\\"tCUGbegVHoXajm\\\",\\n \\\"UiHppQn\\\"\\n ],\\n \\\"tags\\\": [\\n {\\n \\\"id\\\": 727599428,\\n \\\"name\\\": \\\"RemggEDzxPljbrlktdWf\\\"\\n },\\n {\\n \\\"id\\\": 1987753751,\\n \\\"name\\\": \\\"zWqdKAGHMmhPPlomljaNtuvm\\\"\\n },\\n {\\n \\\"id\\\": 1251632392,\\n \\\"name\\\": \\\"BAgtgtKOxZGdsS\\\"\\n },\\n {\\n \\\"id\\\": -1813025208,\\n \\\"name\\\": \\\"OkKxtfAkCMEICbbQDVPi\\\"\\n },\\n {\\n \\\"id\\\": -730110346,\\n \\\"name\\\": \\\"WshDF\\\"\\n },\\n {\\n \\\"id\\\": 2100951153,\\n \\\"name\\\": \\\"yxUFSknQEleIAQCoocl\\\"\\n },\\n {\\n \\\"id\\\": -2135188117,\\n \\\"name\\\": \\\"M\\\"\\n },\\n {\\n \\\"id\\\": 1352243140,\\n \\\"name\\\": \\\"koKHsjysHXW\\\"\\n },\\n {\\n \\\"id\\\": 1696778814,\\n \\\"name\\\": \\\"KaihiyarcZkIzkkquWPZ\\\"\\n },\\n {\\n \\\"id\\\": 659492963,\\n \\\"name\\\": \\\"xqIzulcBPzWMyUpQwQK\\\"\\n },\\n {\\n \\\"id\\\": -2118372841,\\n \\\"name\\\": \\\"naYFGuHmqDqOpfHH\\\"\\n }\\n ],\\n \\\"status\\\": \\\"available\\\"\\n }\\n]\"\n\t\t\t\t\t\t}\n\t\t\t\t\t]\n\t\t\t\t},\n\t\t\t\t{\n\t\t\t\t\t\"name\": \"Find pet by ID\",\n\t\t\t\t\t\"request\": {\n\t\t\t\t\t\t\"url\": {\n\t\t\t\t\t\t\t\"raw\": \"https://petstore-api-2445581593402.apicast.io:443/v2/pet/:petId?user_key={{user_key}}\",\n\t\t\t\t\t\t\t\"protocol\": \"https\",\n\t\t\t\t\t\t\t\"host\": [\n\t\t\t\t\t\t\t\t\"petstore-api-2445581593402\",\n\t\t\t\t\t\t\t\t\"apicast\",\n\t\t\t\t\t\t\t\t\"io\"\n\t\t\t\t\t\t\t],\n\t\t\t\t\t\t\t\"port\": \"443\",\n\t\t\t\t\t\t\t\"path\": [\n\t\t\t\t\t\t\t\t\"v2\",\n\t\t\t\t\t\t\t\t\"pet\",\n\t\t\t\t\t\t\t\t\":petId\"\n\t\t\t\t\t\t\t],\n\t\t\t\t\t\t\t\"query\": [\n\t\t\t\t\t\t\t\t{\n\t\t\t\t\t\t\t\t\t\"key\": \"user_key\",\n\t\t\t\t\t\t\t\t\t\"value\": \"{{user_key}}\",\n\t\t\t\t\t\t\t\t\t\"equals\": true,\n\t\t\t\t\t\t\t\t\t\"description\": \"\"\n\t\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\t],\n\t\t\t\t\t\t\t\"variable\": [\n\t\t\t\t\t\t\t\t{\n\t\t\t\t\t\t\t\t\t\"key\": \"petId\",\n\t\t\t\t\t\t\t\t\t\"value\": \"\"\n\t\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\t]\n\t\t\t\t\t\t},\n\t\t\t\t\t\t\"method\": \"GET\",\n\t\t\t\t\t\t\"header\": [],\n\t\t\t\t\t\t\"body\": {},\n\t\t\t\t\t\t\"description\": \"\"\n\t\t\t\t\t},\n\t\t\t\t\t\"response\": [\n\t\t\t\t\t\t{\n\t\t\t\t\t\t\t\"id\": \"05486047-439f-408d-97e7-a9925107a2a1\",\n\t\t\t\t\t\t\t\"name\": \"get-2\",\n\t\t\t\t\t\t\t\"originalRequest\": {\n\t\t\t\t\t\t\t\t\"url\": {\n\t\t\t\t\t\t\t\t\t\"raw\": \"https://petstore-api-2445581593402.staging.apicast.io:443/v2/pet/:petId?user_key=70f735676ec46351c6699c4bb767878a\",\n\t\t\t\t\t\t\t\t\t\"protocol\": \"https\",\n\t\t\t\t\t\t\t\t\t\"host\": [\n\t\t\t\t\t\t\t\t\t\t\"petstore-api-2445581593402\",\n\t\t\t\t\t\t\t\t\t\t\"staging\",\n\t\t\t\t\t\t\t\t\t\t\"apicast\",\n\t\t\t\t\t\t\t\t\t\t\"io\"\n\t\t\t\t\t\t\t\t\t],\n\t\t\t\t\t\t\t\t\t\"port\": \"443\",\n\t\t\t\t\t\t\t\t\t\"path\": [\n\t\t\t\t\t\t\t\t\t\t\"v2\",\n\t\t\t\t\t\t\t\t\t\t\"pet\",\n\t\t\t\t\t\t\t\t\t\t\":petId\",\n\t\t\t\t\t\t\t\t\t\t\"\"\n\t\t\t\t\t\t\t\t\t],\n\t\t\t\t\t\t\t\t\t\"query\": [\n\t\t\t\t\t\t\t\t\t\t{\n\t\t\t\t\t\t\t\t\t\t\t\"key\": \"user_key\",\n\t\t\t\t\t\t\t\t\t\t\t\"value\": \"70f735676ec46351c6699c4bb767878a\",\n\t\t\t\t\t\t\t\t\t\t\t\"equals\": true,\n\t\t\t\t\t\t\t\t\t\t\t\"description\": \"\"\n\t\t\t\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\t\t\t],\n\t\t\t\t\t\t\t\t\t\"variable\": [\n\t\t\t\t\t\t\t\t\t\t{\n\t\t\t\t\t\t\t\t\t\t\t\"key\": \"petId\",\n\t\t\t\t\t\t\t\t\t\t\t\"value\": \"2\"\n\t\t\t\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\t\t\t]\n\t\t\t\t\t\t\t\t},\n\t\t\t\t\t\t\t\t\"method\": \"GET\",\n\t\t\t\t\t\t\t\t\"header\": [],\n\t\t\t\t\t\t\t\t\"body\": {}\n\t\t\t\t\t\t\t},\n\t\t\t\t\t\t\t\"status\": \"OK\",\n\t\t\t\t\t\t\t\"code\": 200,\n\t\t\t\t\t\t\t\"_postman_previewlanguage\": \"json\",\n\t\t\t\t\t\t\t\"_postman_previewtype\": \"text\",\n\t\t\t\t\t\t\t\"header\": [\n\t\t\t\t\t\t\t\t{\n\t\t\t\t\t\t\t\t\t\"name\": \"Access-Control-Allow-Headers\",\n\t\t\t\t\t\t\t\t\t\"key\": \"Access-Control-Allow-Headers\",\n\t\t\t\t\t\t\t\t\t\"value\": \"Content-Type, api_key, Authorization\",\n\t\t\t\t\t\t\t\t\t\"description\": \"\"\n\t\t\t\t\t\t\t\t},\n\t\t\t\t\t\t\t\t{\n\t\t\t\t\t\t\t\t\t\"name\": \"Access-Control-Allow-Methods\",\n\t\t\t\t\t\t\t\t\t\"key\": \"Access-Control-Allow-Methods\",\n\t\t\t\t\t\t\t\t\t\"value\": \"GET, POST, DELETE, PUT\",\n\t\t\t\t\t\t\t\t\t\"description\": \"\"\n\t\t\t\t\t\t\t\t},\n\t\t\t\t\t\t\t\t{\n\t\t\t\t\t\t\t\t\t\"name\": \"Access-Control-Allow-Origin\",\n\t\t\t\t\t\t\t\t\t\"key\": \"Access-Control-Allow-Origin\",\n\t\t\t\t\t\t\t\t\t\"value\": \"*\",\n\t\t\t\t\t\t\t\t\t\"description\": \"\"\n\t\t\t\t\t\t\t\t},\n\t\t\t\t\t\t\t\t{\n\t\t\t\t\t\t\t\t\t\"name\": \"Connection\",\n\t\t\t\t\t\t\t\t\t\"key\": \"Connection\",\n\t\t\t\t\t\t\t\t\t\"value\": \"keep-alive\",\n\t\t\t\t\t\t\t\t\t\"description\": \"\"\n\t\t\t\t\t\t\t\t},\n\t\t\t\t\t\t\t\t{\n\t\t\t\t\t\t\t\t\t\"name\": \"Content-Length\",\n\t\t\t\t\t\t\t\t\t\"key\": \"Content-Length\",\n\t\t\t\t\t\t\t\t\t\"value\": \"137\",\n\t\t\t\t\t\t\t\t\t\"description\": \"\"\n\t\t\t\t\t\t\t\t},\n\t\t\t\t\t\t\t\t{\n\t\t\t\t\t\t\t\t\t\"name\": \"Content-Type\",\n\t\t\t\t\t\t\t\t\t\"key\": \"Content-Type\",\n\t\t\t\t\t\t\t\t\t\"value\": \"application/json\",\n\t\t\t\t\t\t\t\t\t\"description\": \"\"\n\t\t\t\t\t\t\t\t},\n\t\t\t\t\t\t\t\t{\n\t\t\t\t\t\t\t\t\t\"name\": \"Date\",\n\t\t\t\t\t\t\t\t\t\"key\": \"Date\",\n\t\t\t\t\t\t\t\t\t\"value\": \"Wed, 07 Dec 2016 15:27:18 GMT\",\n\t\t\t\t\t\t\t\t\t\"description\": \"\"\n\t\t\t\t\t\t\t\t},\n\t\t\t\t\t\t\t\t{\n\t\t\t\t\t\t\t\t\t\"name\": \"Server\",\n\t\t\t\t\t\t\t\t\t\"key\": \"Server\",\n\t\t\t\t\t\t\t\t\t\"value\": \"openresty/1.9.7.4\",\n\t\t\t\t\t\t\t\t\t\"description\": \"\"\n\t\t\t\t\t\t\t\t},\n\t\t\t\t\t\t\t\t{\n\t\t\t\t\t\t\t\t\t\"name\": \"X-Powered-By\",\n\t\t\t\t\t\t\t\t\t\"key\": \"X-Powered-By\",\n\t\t\t\t\t\t\t\t\t\"value\": \"3scale API Management - http://www.3scale.net\",\n\t\t\t\t\t\t\t\t\t\"description\": \"\"\n\t\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\t],\n\t\t\t\t\t\t\t\"cookie\": [],\n\t\t\t\t\t\t\t\"responseTime\": 233,\n\t\t\t\t\t\t\t\"body\": \"{\\\"id\\\":2,\\\"category\\\":{\\\"id\\\":1,\\\"name\\\":\\\"Animal\\\"},\\\"name\\\":\\\"cat\\\",\\\"photoUrls\\\":[\\\"string\\\"],\\\"tags\\\":[{\\\"id\\\":1,\\\"name\\\":\\\"domestic\\\"}],\\\"status\\\":\\\"available\\\"}\"\n\t\t\t\t\t\t},\n\t\t\t\t\t\t{\n\t\t\t\t\t\t\t\"id\": \"187fb73f-edbb-47d4-89ae-7e3e4a8cfcbd\",\n\t\t\t\t\t\t\t\"name\": \"get-1\",\n\t\t\t\t\t\t\t\"originalRequest\": {\n\t\t\t\t\t\t\t\t\"url\": {\n\t\t\t\t\t\t\t\t\t\"raw\": \"https://petstore-api-2445581593402.apicast.io:443/v2/pet/:petId?user_key=998bac0775b1d5f588e0a6ca7c11b852\",\n\t\t\t\t\t\t\t\t\t\"protocol\": \"https\",\n\t\t\t\t\t\t\t\t\t\"host\": [\n\t\t\t\t\t\t\t\t\t\t\"petstore-api-2445581593402\",\n\t\t\t\t\t\t\t\t\t\t\"apicast\",\n\t\t\t\t\t\t\t\t\t\t\"io\"\n\t\t\t\t\t\t\t\t\t],\n\t\t\t\t\t\t\t\t\t\"port\": \"443\",\n\t\t\t\t\t\t\t\t\t\"path\": [\n\t\t\t\t\t\t\t\t\t\t\"v2\",\n\t\t\t\t\t\t\t\t\t\t\"pet\",\n\t\t\t\t\t\t\t\t\t\t\":petId\"\n\t\t\t\t\t\t\t\t\t],\n\t\t\t\t\t\t\t\t\t\"query\": [\n\t\t\t\t\t\t\t\t\t\t{\n\t\t\t\t\t\t\t\t\t\t\t\"key\": \"user_key\",\n\t\t\t\t\t\t\t\t\t\t\t\"value\": \"998bac0775b1d5f588e0a6ca7c11b852\",\n\t\t\t\t\t\t\t\t\t\t\t\"equals\": true,\n\t\t\t\t\t\t\t\t\t\t\t\"description\": \"\"\n\t\t\t\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\t\t\t],\n\t\t\t\t\t\t\t\t\t\"variable\": [\n\t\t\t\t\t\t\t\t\t\t{\n\t\t\t\t\t\t\t\t\t\t\t\"key\": \"petId\",\n\t\t\t\t\t\t\t\t\t\t\t\"value\": \"1\"\n\t\t\t\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\t\t\t]\n\t\t\t\t\t\t\t\t},\n\t\t\t\t\t\t\t\t\"method\": \"GET\",\n\t\t\t\t\t\t\t\t\"header\": [],\n\t\t\t\t\t\t\t\t\"body\": {}\n\t\t\t\t\t\t\t},\n\t\t\t\t\t\t\t\"status\": \"Not Found\",\n\t\t\t\t\t\t\t\"code\": 404,\n\t\t\t\t\t\t\t\"_postman_previewlanguage\": \"\",\n\t\t\t\t\t\t\t\"_postman_previewtype\": \"parsed\",\n\t\t\t\t\t\t\t\"header\": [\n\t\t\t\t\t\t\t\t{\n\t\t\t\t\t\t\t\t\t\"key\": \"Access-Control-Allow-Headers\",\n\t\t\t\t\t\t\t\t\t\"value\": \"Content-Type, api_key, Authorization\",\n\t\t\t\t\t\t\t\t\t\"description\": \"\",\n\t\t\t\t\t\t\t\t\t\"type\": \"text\",\n\t\t\t\t\t\t\t\t\t\"name\": \"Access-Control-Allow-Headers\"\n\t\t\t\t\t\t\t\t},\n\t\t\t\t\t\t\t\t{\n\t\t\t\t\t\t\t\t\t\"key\": \"Access-Control-Allow-Methods\",\n\t\t\t\t\t\t\t\t\t\"value\": \"GET, POST, DELETE, PUT\",\n\t\t\t\t\t\t\t\t\t\"description\": \"\",\n\t\t\t\t\t\t\t\t\t\"type\": \"text\",\n\t\t\t\t\t\t\t\t\t\"name\": \"Access-Control-Allow-Methods\"\n\t\t\t\t\t\t\t\t},\n\t\t\t\t\t\t\t\t{\n\t\t\t\t\t\t\t\t\t\"key\": \"Access-Control-Allow-Origin\",\n\t\t\t\t\t\t\t\t\t\"value\": \"*\",\n\t\t\t\t\t\t\t\t\t\"description\": \"\",\n\t\t\t\t\t\t\t\t\t\"type\": \"text\",\n\t\t\t\t\t\t\t\t\t\"name\": \"Access-Control-Allow-Origin\"\n\t\t\t\t\t\t\t\t},\n\t\t\t\t\t\t\t\t{\n\t\t\t\t\t\t\t\t\t\"key\": \"Content-Type\",\n\t\t\t\t\t\t\t\t\t\"value\": \"application/json\",\n\t\t\t\t\t\t\t\t\t\"name\": \"Content-Type\",\n\t\t\t\t\t\t\t\t\t\"description\": \"\"\n\t\t\t\t\t\t\t\t},\n\t\t\t\t\t\t\t\t{\n\t\t\t\t\t\t\t\t\t\"key\": \"Content-Length\",\n\t\t\t\t\t\t\t\t\t\"value\": \"0\",\n\t\t\t\t\t\t\t\t\t\"description\": \"\",\n\t\t\t\t\t\t\t\t\t\"type\": \"text\",\n\t\t\t\t\t\t\t\t\t\"name\": \"Content-Length\"\n\t\t\t\t\t\t\t\t},\n\t\t\t\t\t\t\t\t{\n\t\t\t\t\t\t\t\t\t\"key\": \"Server\",\n\t\t\t\t\t\t\t\t\t\"value\": \"openresty/1.9.7.4\",\n\t\t\t\t\t\t\t\t\t\"description\": \"\",\n\t\t\t\t\t\t\t\t\t\"type\": \"text\",\n\t\t\t\t\t\t\t\t\t\"name\": \"Server\"\n\t\t\t\t\t\t\t\t},\n\t\t\t\t\t\t\t\t{\n\t\t\t\t\t\t\t\t\t\"key\": \"Date\",\n\t\t\t\t\t\t\t\t\t\"value\": \"Wed, 07 Dec 2016 15:27:22 GMT\",\n\t\t\t\t\t\t\t\t\t\"description\": \"\",\n\t\t\t\t\t\t\t\t\t\"type\": \"text\",\n\t\t\t\t\t\t\t\t\t\"name\": \"Date\"\n\t\t\t\t\t\t\t\t},\n\t\t\t\t\t\t\t\t{\n\t\t\t\t\t\t\t\t\t\"key\": \"X-Powered-By\",\n\t\t\t\t\t\t\t\t\t\"value\": \"3scale API Management - http://www.3scale.net\",\n\t\t\t\t\t\t\t\t\t\"description\": \"\",\n\t\t\t\t\t\t\t\t\t\"type\": \"text\",\n\t\t\t\t\t\t\t\t\t\"name\": \"X-Powered-By\"\n\t\t\t\t\t\t\t\t},\n\t\t\t\t\t\t\t\t{\n\t\t\t\t\t\t\t\t\t\"key\": \"Connection\",\n\t\t\t\t\t\t\t\t\t\"value\": \"keep-alive\",\n\t\t\t\t\t\t\t\t\t\"description\": \"\",\n\t\t\t\t\t\t\t\t\t\"type\": \"text\",\n\t\t\t\t\t\t\t\t\t\"name\": \"Connection\"\n\t\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\t],\n\t\t\t\t\t\t\t\"cookie\": [],\n\t\t\t\t\t\t\t\"responseTime\": 0,\n\t\t\t\t\t\t\t\"body\": \"\"\n\t\t\t\t\t\t}\n\t\t\t\t\t]\n\t\t\t\t}\n\t\t\t]\n\t\t}\n\t]\n}\n", + "type": "POSTMAN_COLLECTION", + "serviceId": "64b99e83e2dbae25009ded78", + "sourceArtifact": "PetstoreAPI-collection.json", + "operations": null + }, + { + "id": "65c6170eab2f0b1c5c395dcd", + "name": "io.github.microcks.grpc.hello.v1.HelloService-v1.proto", + "path": null, + "content": "syntax = \"proto3\";\n\npackage io.github.microcks.grpc.hello.v1;\n\noption java_multiple_files = true;\n\nmessage HelloRequest {\n string firstname = 1;\n string lastname = 2;\n}\n\nmessage HelloResponse {\n string greeting = 1;\n}\n\nservice HelloService {\n rpc greeting(HelloRequest) returns (HelloResponse);\n}", + "type": "PROTOBUF_SCHEMA", + "serviceId": "65c6170eab2f0b1c5c395dcc", + "sourceArtifact": "https://raw.githubusercontent.com/microcks/microcks/master/samples/hello-v1.proto", + "operations": null + }, + { + "id": "65c6170eab2f0b1c5c395dce", + "name": "io.github.microcks.grpc.hello.v1.HelloService-v1.pbb", + "path": null, + "content": "CtcCCjNtaWNyb2Nrcy0xNzA3NDgwODQ1MTM0MTE1OTQwNzk5OTI3OTM1MzA2NTcuZG93bmxvYWQSIGlvLmdpdGh1Yi5taWNyb2Nrcy5ncnBjLmhlbGxvLnYxIkgKDEhlbGxvUmVxdWVzdBIcCglmaXJzdG5hbWUYASABKAlSCWZpcnN0bmFtZRIaCghsYXN0bmFtZRgCIAEoCVIIbGFzdG5hbWUiKwoNSGVsbG9SZXNwb25zZRIaCghncmVldGluZxgBIAEoCVIIZ3JlZXRpbmcyewoMSGVsbG9TZXJ2aWNlEmsKCGdyZWV0aW5nEi4uaW8uZ2l0aHViLm1pY3JvY2tzLmdycGMuaGVsbG8udjEuSGVsbG9SZXF1ZXN0Gi8uaW8uZ2l0aHViLm1pY3JvY2tzLmdycGMuaGVsbG8udjEuSGVsbG9SZXNwb25zZUICUAFiBnByb3RvMw==", + "type": "PROTOBUF_DESCRIPTOR", + "serviceId": "65c6170eab2f0b1c5c395dcc", + "sourceArtifact": "https://raw.githubusercontent.com/microcks/microcks/master/samples/hello-v1.proto", + "operations": null + }, + { + "id": "65c6192bab2f0b1c5c395dd0", + "name": "io.github.microcks.grpc.hello.v1.HelloService-v1.json", + "path": null, + "content": "{\n\t\"info\": {\n\t\t\"_postman_id\": \"448f2755-4b3c-45a7-b6d4-af16d8110e9d\",\n\t\t\"name\": \"io.github.microcks.grpc.hello.v1.HelloService\",\n\t\t\"description\": \"version=v1 - This collection holds mock messages for HelloService v1 GRPC\",\n\t\t\"schema\": \"https://schema.getpostman.com/json/collection/v2.1.0/collection.json\"\n\t},\n\t\"item\": [\n\t\t{\n\t\t\t\"name\": \"greeting\",\n\t\t\t\"item\": [\n\t\t\t\t{\n\t\t\t\t\t\"name\": \"greeting\",\n\t\t\t\t\t\"request\": {\n\t\t\t\t\t\t\"method\": \"POST\",\n\t\t\t\t\t\t\"header\": [],\n\t\t\t\t\t\t\"url\": {\n\t\t\t\t\t\t\t\"raw\": \"http:///greeting\",\n\t\t\t\t\t\t\t\"protocol\": \"http\",\n\t\t\t\t\t\t\t\"path\": [\n\t\t\t\t\t\t\t\t\"greeting\"\n\t\t\t\t\t\t\t]\n\t\t\t\t\t\t}\n\t\t\t\t\t},\n\t\t\t\t\t\"response\": [\n\t\t\t\t\t\t{\n\t\t\t\t\t\t\t\"name\": \"John\",\n\t\t\t\t\t\t\t\"originalRequest\": {\n\t\t\t\t\t\t\t\t\"method\": \"POST\",\n\t\t\t\t\t\t\t\t\"header\": [\n\t\t\t\t\t\t\t\t\t{\n\t\t\t\t\t\t\t\t\t\t\"key\": \"Content-Type\",\n\t\t\t\t\t\t\t\t\t\t\"name\": \"Content-Type\",\n\t\t\t\t\t\t\t\t\t\t\"value\": \"application/json\",\n\t\t\t\t\t\t\t\t\t\t\"type\": \"text\"\n\t\t\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\t\t],\n\t\t\t\t\t\t\t\t\"body\": {\n\t\t\t\t\t\t\t\t\t\"mode\": \"raw\",\n\t\t\t\t\t\t\t\t\t\"raw\": \"{\\n \\\"firstname\\\": \\\"John\\\",\\n \\\"lastname\\\": \\\"Doe\\\"\\n}\",\n\t\t\t\t\t\t\t\t\t\"options\": {\n\t\t\t\t\t\t\t\t\t\t\"raw\": {\n\t\t\t\t\t\t\t\t\t\t\t\"language\": \"json\"\n\t\t\t\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\t\t},\n\t\t\t\t\t\t\t\t\"url\": {\n\t\t\t\t\t\t\t\t\t\"raw\": \"http:///greeting\",\n\t\t\t\t\t\t\t\t\t\"protocol\": \"http\",\n\t\t\t\t\t\t\t\t\t\"path\": [\n\t\t\t\t\t\t\t\t\t\t\"greeting\"\n\t\t\t\t\t\t\t\t\t]\n\t\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\t},\n\t\t\t\t\t\t\t\"_postman_previewlanguage\": \"json\",\n\t\t\t\t\t\t\t\"header\": null,\n\t\t\t\t\t\t\t\"cookie\": [],\n\t\t\t\t\t\t\t\"body\": \"{\\n \\\"greeting\\\": \\\"Hello John Doe !\\\"\\n}\"\n\t\t\t\t\t\t},\n\t\t\t\t\t\t{\n\t\t\t\t\t\t\t\"name\": \"Laurent\",\n\t\t\t\t\t\t\t\"originalRequest\": {\n\t\t\t\t\t\t\t\t\"method\": \"POST\",\n\t\t\t\t\t\t\t\t\"header\": [\n\t\t\t\t\t\t\t\t\t{\n\t\t\t\t\t\t\t\t\t\t\"key\": \"Content-Type\",\n\t\t\t\t\t\t\t\t\t\t\"name\": \"Content-Type\",\n\t\t\t\t\t\t\t\t\t\t\"value\": \"application/json\",\n\t\t\t\t\t\t\t\t\t\t\"type\": \"text\"\n\t\t\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\t\t],\n\t\t\t\t\t\t\t\t\"body\": {\n\t\t\t\t\t\t\t\t\t\"mode\": \"raw\",\n\t\t\t\t\t\t\t\t\t\"raw\": \"{\\n \\\"firstname\\\": \\\"Laurent\\\",\\n \\\"lastname\\\": \\\"Broudoux\\\"\\n}\",\n\t\t\t\t\t\t\t\t\t\"options\": {\n\t\t\t\t\t\t\t\t\t\t\"raw\": {\n\t\t\t\t\t\t\t\t\t\t\t\"language\": \"json\"\n\t\t\t\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\t\t},\n\t\t\t\t\t\t\t\t\"url\": {\n\t\t\t\t\t\t\t\t\t\"raw\": \"http:///greeting\",\n\t\t\t\t\t\t\t\t\t\"protocol\": \"http\",\n\t\t\t\t\t\t\t\t\t\"path\": [\n\t\t\t\t\t\t\t\t\t\t\"greeting\"\n\t\t\t\t\t\t\t\t\t]\n\t\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\t},\n\t\t\t\t\t\t\t\"_postman_previewlanguage\": \"json\",\n\t\t\t\t\t\t\t\"header\": null,\n\t\t\t\t\t\t\t\"cookie\": [],\n\t\t\t\t\t\t\t\"body\": \"{\\n \\\"greeting\\\": \\\"Hello Laurent Broudoux !\\\"\\n}\"\n\t\t\t\t\t\t}\n\t\t\t\t\t]\n\t\t\t\t}\n\t\t\t]\n\t\t}\n\t]\n}", + "type": "POSTMAN_COLLECTION", + "serviceId": "65c6170eab2f0b1c5c395dcc", + "sourceArtifact": "HelloService.postman.json", + "operations": null + }, + { + "id": "65fd7a7a1f846c7939d014d0", + "name": "Movie Graph API-1.0.graphql", + "path": null, + "content": "# microcksId: Movie Graph API : 1.0\nschema {\n query: Query\n mutation: Mutation\n}\ntype Film {\n id: String!\n title: String!\n episodeID: Int!\n director: String!\n starCount: Int!\n rating: Float!\n}\n\ntype FilmsConnection {\n totalCount: Int!\n films: [Film]\n}\n\ninput Review {\n comment: String\n rating: Int\n}\n\ntype Query {\n allFilms: FilmsConnection\n film(id: String): Film\n}\n\ntype Mutation {\n addStar(filmId: String): Film\n addReview(filmId: String, review: Review): Film\n}\n\n", + "type": "GRAPHQL_SCHEMA", + "serviceId": "65fd7a7a1f846c7939d014cf", + "sourceArtifact": "https://raw.githubusercontent.com/microcks/microcks/master/samples/films.graphql", + "operations": null + }, + { + "id": "65fd7a7b1f846c7939d014d2", + "name": "Movie Graph API-1.0.json", + "path": null, + "content": "{\n\t\"info\": {\n\t\t\"_postman_id\": \"7c00b563-d454-421a-a3b0-17c4e3254cb9\",\n\t\t\"name\": \"Movie Graph API\",\n\t\t\"description\": \"version=1.0 - A Graph API for querying movies\",\n\t\t\"schema\": \"https://schema.getpostman.com/json/collection/v2.1.0/collection.json\"\n\t},\n\t\"item\": [\n\t\t{\n\t\t\t\"name\": \"queries\",\n\t\t\t\"item\": [\n\t\t\t\t{\n\t\t\t\t\t\"name\": \"allFilms\",\n\t\t\t\t\t\"request\": {\n\t\t\t\t\t\t\"method\": \"POST\",\n\t\t\t\t\t\t\"header\": [],\n\t\t\t\t\t\t\"body\": {\n\t\t\t\t\t\t\t\"mode\": \"graphql\",\n\t\t\t\t\t\t\t\"graphql\": {\n\t\t\t\t\t\t\t\t\"query\": \"query allFilms {\\n allFilms {\\n totalCount\\n films {\\n id\\n title\\n episodeID\\n director\\n starCount\\n rating\\n }\\n }\\n}\",\n\t\t\t\t\t\t\t\t\"variables\": \"{}\"\n\t\t\t\t\t\t\t}\n\t\t\t\t\t\t},\n\t\t\t\t\t\t\"url\": {\n\t\t\t\t\t\t\t\"raw\": \"http://allFilms\",\n\t\t\t\t\t\t\t\"protocol\": \"http\",\n\t\t\t\t\t\t\t\"host\": [\n\t\t\t\t\t\t\t\t\"allFilms\"\n\t\t\t\t\t\t\t]\n\t\t\t\t\t\t}\n\t\t\t\t\t},\n\t\t\t\t\t\"response\": [\n\t\t\t\t\t\t{\n\t\t\t\t\t\t\t\"name\": \"allFilms\",\n\t\t\t\t\t\t\t\"originalRequest\": {\n\t\t\t\t\t\t\t\t\"method\": \"POST\",\n\t\t\t\t\t\t\t\t\"header\": [],\n\t\t\t\t\t\t\t\t\"body\": {\n\t\t\t\t\t\t\t\t\t\"mode\": \"graphql\",\n\t\t\t\t\t\t\t\t\t\"graphql\": {\n\t\t\t\t\t\t\t\t\t\t\"query\": \"query allFilms {\\n allFilms {\\n films {\\n id\\n title\\n episodeID\\n director\\n starCount\\n rating\\n }\\n }\\n}\",\n\t\t\t\t\t\t\t\t\t\t\"variables\": \"{}\"\n\t\t\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\t\t},\n\t\t\t\t\t\t\t\t\"url\": {\n\t\t\t\t\t\t\t\t\t\"raw\": \"{{url}}\",\n\t\t\t\t\t\t\t\t\t\"host\": [\n\t\t\t\t\t\t\t\t\t\t\"{{url}}\"\n\t\t\t\t\t\t\t\t\t]\n\t\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\t},\n\t\t\t\t\t\t\t\"status\": \"OK\",\n\t\t\t\t\t\t\t\"code\": 200,\n\t\t\t\t\t\t\t\"_postman_previewlanguage\": \"json\",\n\t\t\t\t\t\t\t\"header\": null,\n\t\t\t\t\t\t\t\"cookie\": [],\n\t\t\t\t\t\t\t\"body\": \"{\\n \\\"data\\\": {\\n \\\"allFilms\\\": {\\n \\\"films\\\": [\\n {\\n \\\"id\\\": \\\"ZmlsbXM6MQ==\\\",\\n \\\"title\\\": \\\"A New Hope\\\",\\n \\\"episodeID\\\": 4,\\n \\\"director\\\": \\\"George Lucas\\\",\\n \\\"starCount\\\": 432,\\n \\\"rating\\\": 4.3\\n },\\n {\\n \\\"id\\\": \\\"ZmlsbXM6Mg==\\\",\\n \\\"title\\\": \\\"The Empire Strikes Back\\\",\\n \\\"episodeID\\\": 5,\\n \\\"director\\\": \\\"Irvin Kershner\\\",\\n \\\"starCount\\\": 433,\\n \\\"rating\\\": 4.3\\n },\\n {\\n \\\"id\\\": \\\"ZmlsbXM6Mw==\\\",\\n \\\"title\\\": \\\"Return of the Jedi\\\",\\n \\\"episodeID\\\": 6,\\n \\\"director\\\": \\\"Richard Marquand\\\",\\n \\\"starCount\\\": 434,\\n \\\"rating\\\": 4.3\\n },\\n {\\n \\\"id\\\": \\\"ZmlsbXM6NA==\\\",\\n \\\"title\\\": \\\"The Phantom Menace\\\",\\n \\\"episodeID\\\": 1,\\n \\\"director\\\": \\\"George Lucas\\\",\\n \\\"starCount\\\": 252,\\n \\\"rating\\\": 3.2\\n },\\n {\\n \\\"id\\\": \\\"ZmlsbXM6NQ==\\\",\\n \\\"title\\\": \\\"Attack of the Clones\\\",\\n \\\"episodeID\\\": 2,\\n \\\"director\\\": \\\"George Lucas\\\",\\n \\\"starCount\\\": 320,\\n \\\"rating\\\": 3.9\\n },\\n {\\n \\\"id\\\": \\\"ZmlsbXM6Ng==\\\",\\n \\\"title\\\": \\\"Revenge of the Sith\\\",\\n \\\"episodeID\\\": 3,\\n \\\"director\\\": \\\"George Lucas\\\",\\n \\\"starCount\\\": 410,\\n \\\"rating\\\": 4.1\\n }\\n ]\\n }\\n }\\n}\"\n\t\t\t\t\t\t}\n\t\t\t\t\t]\n\t\t\t\t},\n\t\t\t\t{\n\t\t\t\t\t\"name\": \"film\",\n\t\t\t\t\t\"request\": {\n\t\t\t\t\t\t\"method\": \"POST\",\n\t\t\t\t\t\t\"header\": [],\n\t\t\t\t\t\t\"body\": {\n\t\t\t\t\t\t\t\"mode\": \"graphql\",\n\t\t\t\t\t\t\t\"graphql\": {\n\t\t\t\t\t\t\t\t\"query\": \"query film ($id: String) {\\n film (id: $id) {\\n id\\n title\\n episodeID\\n director\\n starCount\\n rating\\n }\\n}\",\n\t\t\t\t\t\t\t\t\"variables\": \"{\\n \\\"id\\\": \\\"\\\"\\n}\"\n\t\t\t\t\t\t\t}\n\t\t\t\t\t\t},\n\t\t\t\t\t\t\"url\": {\n\t\t\t\t\t\t\t\"raw\": \"http://film\",\n\t\t\t\t\t\t\t\"protocol\": \"http\",\n\t\t\t\t\t\t\t\"host\": [\n\t\t\t\t\t\t\t\t\"film\"\n\t\t\t\t\t\t\t]\n\t\t\t\t\t\t}\n\t\t\t\t\t},\n\t\t\t\t\t\"response\": [\n\t\t\t\t\t\t{\n\t\t\t\t\t\t\t\"name\": \"film ZmlsbXM6MQ==\",\n\t\t\t\t\t\t\t\"originalRequest\": {\n\t\t\t\t\t\t\t\t\"method\": \"POST\",\n\t\t\t\t\t\t\t\t\"header\": [],\n\t\t\t\t\t\t\t\t\"body\": {\n\t\t\t\t\t\t\t\t\t\"mode\": \"graphql\",\n\t\t\t\t\t\t\t\t\t\"graphql\": {\n\t\t\t\t\t\t\t\t\t\t\"query\": \"query film ($id: String) {\\n film (id: $id) {\\n id\\n title\\n episodeID\\n director\\n starCount\\n rating\\n }\\n}\",\n\t\t\t\t\t\t\t\t\t\t\"variables\": \"{\\n \\\"id\\\": \\\"ZmlsbXM6MQ==\\\"\\n}\"\n\t\t\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\t\t},\n\t\t\t\t\t\t\t\t\"url\": {\n\t\t\t\t\t\t\t\t\t\"raw\": \"{{url}}\",\n\t\t\t\t\t\t\t\t\t\"host\": [\n\t\t\t\t\t\t\t\t\t\t\"{{url}}\"\n\t\t\t\t\t\t\t\t\t]\n\t\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\t},\n\t\t\t\t\t\t\t\"status\": \"OK\",\n\t\t\t\t\t\t\t\"code\": 200,\n\t\t\t\t\t\t\t\"_postman_previewlanguage\": \"json\",\n\t\t\t\t\t\t\t\"header\": null,\n\t\t\t\t\t\t\t\"cookie\": [],\n\t\t\t\t\t\t\t\"body\": \"{\\n \\\"data\\\": {\\n \\\"film\\\": {\\n \\\"id\\\": \\\"ZmlsbXM6MQ==\\\",\\n \\\"title\\\": \\\"A New Hope\\\",\\n \\\"episodeID\\\": 4,\\n \\\"director\\\": \\\"George Lucas\\\",\\n \\\"starCount\\\": 432,\\n \\\"rating\\\": 4.3\\n }\\n }\\n}\"\n\t\t\t\t\t\t},\n\t\t\t\t\t\t{\n\t\t\t\t\t\t\t\"name\": \"film ZmlsbXM6Mg==\",\n\t\t\t\t\t\t\t\"originalRequest\": {\n\t\t\t\t\t\t\t\t\"method\": \"POST\",\n\t\t\t\t\t\t\t\t\"header\": [],\n\t\t\t\t\t\t\t\t\"body\": {\n\t\t\t\t\t\t\t\t\t\"mode\": \"graphql\",\n\t\t\t\t\t\t\t\t\t\"graphql\": {\n\t\t\t\t\t\t\t\t\t\t\"query\": \"query film ($id: String) {\\n film (id: $id) {\\n id\\n title\\n episodeID\\n director\\n starCount\\n rating\\n }\\n}\",\n\t\t\t\t\t\t\t\t\t\t\"variables\": \"{\\n \\\"id\\\": \\\"ZmlsbXM6Mg==\\\"\\n}\"\n\t\t\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\t\t},\n\t\t\t\t\t\t\t\t\"url\": {\n\t\t\t\t\t\t\t\t\t\"raw\": \"{{url}}\",\n\t\t\t\t\t\t\t\t\t\"host\": [\n\t\t\t\t\t\t\t\t\t\t\"{{url}}\"\n\t\t\t\t\t\t\t\t\t]\n\t\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\t},\n\t\t\t\t\t\t\t\"status\": \"OK\",\n\t\t\t\t\t\t\t\"code\": 200,\n\t\t\t\t\t\t\t\"_postman_previewlanguage\": \"json\",\n\t\t\t\t\t\t\t\"header\": null,\n\t\t\t\t\t\t\t\"cookie\": [],\n\t\t\t\t\t\t\t\"body\": \"{\\n \\\"data\\\": {\\n \\\"film\\\": {\\n \\\"id\\\": \\\"ZmlsbXM6Mg==\\\",\\n \\\"title\\\": \\\"The Empire Strikes Back\\\",\\n \\\"episodeID\\\": 5,\\n \\\"director\\\": \\\"Irvin Kershner\\\",\\n \\\"starCount\\\": 433,\\n \\\"rating\\\": 4.3\\n }\\n }\\n}\"\n\t\t\t\t\t\t}\n\t\t\t\t\t]\n\t\t\t\t}\n\t\t\t]\n\t\t},\n\t\t{\n\t\t\t\"name\": \"mutations\",\n\t\t\t\"item\": [\n\t\t\t\t{\n\t\t\t\t\t\"name\": \"addStar\",\n\t\t\t\t\t\"request\": {\n\t\t\t\t\t\t\"method\": \"POST\",\n\t\t\t\t\t\t\"header\": [],\n\t\t\t\t\t\t\"body\": {\n\t\t\t\t\t\t\t\"mode\": \"graphql\",\n\t\t\t\t\t\t\t\"graphql\": {\n\t\t\t\t\t\t\t\t\"query\": \"mutation AddStar($filmId: String) {\\n addStar(filmId: $filmId) {\\n id\\n starCount\\n rating\\n }\\n}\",\n\t\t\t\t\t\t\t\t\"variables\": \"{\\n \\\"filmId\\\": \\\"\\\"\\n}\"\n\t\t\t\t\t\t\t}\n\t\t\t\t\t\t},\n\t\t\t\t\t\t\"url\": {\n\t\t\t\t\t\t\t\"raw\": \"http://addStar\",\n\t\t\t\t\t\t\t\"protocol\": \"http\",\n\t\t\t\t\t\t\t\"host\": [\n\t\t\t\t\t\t\t\t\"addStar\"\n\t\t\t\t\t\t\t]\n\t\t\t\t\t\t}\n\t\t\t\t\t},\n\t\t\t\t\t\"response\": [\n\t\t\t\t\t\t{\n\t\t\t\t\t\t\t\"name\": \"addStar to ZmlsbXM6Mg==\",\n\t\t\t\t\t\t\t\"originalRequest\": {\n\t\t\t\t\t\t\t\t\"method\": \"POST\",\n\t\t\t\t\t\t\t\t\"header\": [],\n\t\t\t\t\t\t\t\t\"body\": {\n\t\t\t\t\t\t\t\t\t\"mode\": \"graphql\",\n\t\t\t\t\t\t\t\t\t\"graphql\": {\n\t\t\t\t\t\t\t\t\t\t\"query\": \"mutation AddStar($filmId: String) {\\n addStar(filmId: $filmId) {\\n id\\n title\\n episodeID\\n director\\n starCount\\n rating\\n }\\n}\",\n\t\t\t\t\t\t\t\t\t\t\"variables\": \"{\\n \\\"filmId\\\": \\\"ZmlsbXM6Mg==\\\"\\n}\"\n\t\t\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\t\t},\n\t\t\t\t\t\t\t\t\"url\": {\n\t\t\t\t\t\t\t\t\t\"raw\": \"http://addStar\",\n\t\t\t\t\t\t\t\t\t\"protocol\": \"http\",\n\t\t\t\t\t\t\t\t\t\"host\": [\n\t\t\t\t\t\t\t\t\t\t\"addStar\"\n\t\t\t\t\t\t\t\t\t]\n\t\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\t},\n\t\t\t\t\t\t\t\"status\": \"OK\",\n\t\t\t\t\t\t\t\"code\": 200,\n\t\t\t\t\t\t\t\"_postman_previewlanguage\": \"json\",\n\t\t\t\t\t\t\t\"header\": null,\n\t\t\t\t\t\t\t\"cookie\": [],\n\t\t\t\t\t\t\t\"body\": \"{\\n \\\"data\\\": {\\n \\\"addStar\\\": {\\n \\\"id\\\": \\\"ZmlsbXM6Mg==\\\",\\n \\\"title\\\": \\\"The Empire Strikes Back\\\",\\n \\\"episodeID\\\": 5,\\n \\\"director\\\": \\\"Irvin Kershner\\\",\\n \\\"starCount\\\": 434,\\n \\\"rating\\\": 4.3\\n }\\n }\\n}\"\n\t\t\t\t\t\t}\n\t\t\t\t\t]\n\t\t\t\t},\n\t\t\t\t{\n\t\t\t\t\t\"name\": \"addReview\",\n\t\t\t\t\t\"request\": {\n\t\t\t\t\t\t\"method\": \"POST\",\n\t\t\t\t\t\t\"header\": [],\n\t\t\t\t\t\t\"url\": {\n\t\t\t\t\t\t\t\"raw\": \"http://addReview\",\n\t\t\t\t\t\t\t\"protocol\": \"http\",\n\t\t\t\t\t\t\t\"host\": [\n\t\t\t\t\t\t\t\t\"addReview\"\n\t\t\t\t\t\t\t]\n\t\t\t\t\t\t}\n\t\t\t\t\t},\n\t\t\t\t\t\"response\": [\n\t\t\t\t\t\t{\n\t\t\t\t\t\t\t\"name\": \"addReview to ZmlsbXM6Mg==\",\n\t\t\t\t\t\t\t\"originalRequest\": {\n\t\t\t\t\t\t\t\t\"method\": \"POST\",\n\t\t\t\t\t\t\t\t\"header\": [],\n\t\t\t\t\t\t\t\t\"body\": {\n\t\t\t\t\t\t\t\t\t\"mode\": \"graphql\",\n\t\t\t\t\t\t\t\t\t\"graphql\": {\n\t\t\t\t\t\t\t\t\t\t\"query\": \"mutation AddReview($filmId: String, $review: Review) {\\n addReview(filmId: $filmId, review: $review) {\\n id\\n title\\n episodeID\\n director\\n starCount\\n rating\\n }\\n}\\n\",\n\t\t\t\t\t\t\t\t\t\t\"variables\": \"{\\n \\\"filmId\\\": \\\"ZmlsbXM6Mg==\\\",\\n \\\"review\\\": {\\n \\\"comment\\\": \\\"Awesome!\\\",\\n \\\"rating\\\": 5\\n }\\n}\\n\"\n\t\t\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\t\t},\n\t\t\t\t\t\t\t\t\"url\": {\n\t\t\t\t\t\t\t\t\t\"raw\": \"http://addReview\",\n\t\t\t\t\t\t\t\t\t\"protocol\": \"http\",\n\t\t\t\t\t\t\t\t\t\"host\": [\n\t\t\t\t\t\t\t\t\t\t\"addReview\"\n\t\t\t\t\t\t\t\t\t]\n\t\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\t},\n\t\t\t\t\t\t\t\"status\": \"OK\",\n\t\t\t\t\t\t\t\"code\": 200,\n\t\t\t\t\t\t\t\"_postman_previewlanguage\": \"json\",\n\t\t\t\t\t\t\t\"header\": null,\n\t\t\t\t\t\t\t\"cookie\": [],\n\t\t\t\t\t\t\t\"body\": \"{\\n \\\"data\\\": {\\n \\\"addReview\\\": {\\n \\\"id\\\": \\\"ZmlsbXM6Mg==\\\",\\n \\\"title\\\": \\\"The Empire Strikes Back\\\",\\n \\\"episodeID\\\": 5,\\n \\\"director\\\": \\\"Irvin Kershner\\\",\\n \\\"starCount\\\": 433,\\n \\\"rating\\\": 4.4\\n }\\n }\\n}\"\n\t\t\t\t\t\t}\n\t\t\t\t\t]\n\t\t\t\t}\n\t\t\t]\n\t\t}\n\t],\n\t\"variable\": [\n\t\t{\n\t\t\t\"key\": \"url\",\n\t\t\t\"value\": \"\",\n\t\t\t\"type\": \"any\",\n\t\t\t\"description\": \"URL for the request.\"\n\t\t}\n\t]\n}", + "type": "POSTMAN_COLLECTION", + "serviceId": "65fd7a7a1f846c7939d014cf", + "sourceArtifact": "https://raw.githubusercontent.com/microcks/microcks/master/samples/films-postman.json", + "operations": null + } + ], + "requests": [ + { + "name": "film ZmlsbXM6MQ==", + "content": "{\"query\": \"query film ($id: String) {\\n film (id: $id) {\\n id\\n title\\n episodeID\\n director\\n starCount\\n rating\\n }\\n}\", \"variables\": {\n \"id\": \"ZmlsbXM6MQ==\"\n}}", + "operationId": "65fd7a7a1f846c7939d014cf-film", + "testCaseId": null, + "sourceArtifact": "https://raw.githubusercontent.com/microcks/microcks/master/samples/films-postman.json", + "headers": null, + "id": "65fd7a7b1f846c7939d014d6", + "responseId": "65fd7a7b1f846c7939d014d5", + "queryParameters": null + }, + { + "name": "film ZmlsbXM6Mg==", + "content": "{\"query\": \"query film ($id: String) {\\n film (id: $id) {\\n id\\n title\\n episodeID\\n director\\n starCount\\n rating\\n }\\n}\", \"variables\": {\n \"id\": \"ZmlsbXM6Mg==\"\n}}", + "operationId": "65fd7a7a1f846c7939d014cf-film", + "testCaseId": null, + "sourceArtifact": "https://raw.githubusercontent.com/microcks/microcks/master/samples/films-postman.json", + "headers": null, + "id": "65fd7a7b1f846c7939d014d8", + "responseId": "65fd7a7b1f846c7939d014d7", + "queryParameters": null + }, + { + "name": "allFilms", + "content": "{\"query\": \"query allFilms {\\n allFilms {\\n films {\\n id\\n title\\n episodeID\\n director\\n starCount\\n rating\\n }\\n }\\n}\"}", + "operationId": "65fd7a7a1f846c7939d014cf-allFilms", + "testCaseId": null, + "sourceArtifact": "https://raw.githubusercontent.com/microcks/microcks/master/samples/films-postman.json", + "headers": null, + "id": "65fd7a7b1f846c7939d014d4", + "responseId": "65fd7a7b1f846c7939d014d3", + "queryParameters": null + }, + { + "name": "addStar to ZmlsbXM6Mg==", + "content": "{\"query\": \"mutation AddStar($filmId: String) {\\n addStar(filmId: $filmId) {\\n id\\n title\\n episodeID\\n director\\n starCount\\n rating\\n }\\n}\", \"variables\": {\n \"filmId\": \"ZmlsbXM6Mg==\"\n}}", + "operationId": "65fd7a7a1f846c7939d014cf-addStar", + "testCaseId": null, + "sourceArtifact": "https://raw.githubusercontent.com/microcks/microcks/master/samples/films-postman.json", + "headers": null, + "id": "65fd7a7b1f846c7939d014da", + "responseId": "65fd7a7b1f846c7939d014d9", + "queryParameters": null + }, + { + "name": "addReview to ZmlsbXM6Mg==", + "content": "{\"query\": \"mutation AddReview($filmId: String, $review: Review) {\\n addReview(filmId: $filmId, review: $review) {\\n id\\n title\\n episodeID\\n director\\n starCount\\n rating\\n }\\n}\\n\", \"variables\": {\n \"filmId\": \"ZmlsbXM6Mg==\",\n \"review\": {\n \"comment\": \"Awesome!\",\n \"rating\": 5\n }\n}\n}", + "operationId": "65fd7a7a1f846c7939d014cf-addReview", + "testCaseId": null, + "sourceArtifact": "https://raw.githubusercontent.com/microcks/microcks/master/samples/films-postman.json", + "headers": null, + "id": "65fd7a7b1f846c7939d014dc", + "responseId": "65fd7a7b1f846c7939d014db", + "queryParameters": null + }, + { + "name": "John", + "content": "{\n \"firstname\": \"John\",\n \"lastname\": \"Doe\"\n}", + "operationId": "65c6170eab2f0b1c5c395dcc-greeting", + "testCaseId": null, + "sourceArtifact": "HelloService.postman.json", + "headers": [ + { + "name": "Content-Type", + "values": [ "application/json" ] + } + ], + "id": "65c6192bab2f0b1c5c395dd2", + "responseId": "65c6192bab2f0b1c5c395dd1", + "queryParameters": null + }, + { + "name": "Laurent", + "content": "{\n \"firstname\": \"Laurent\",\n \"lastname\": \"Broudoux\"\n}", + "operationId": "65c6170eab2f0b1c5c395dcc-greeting", + "testCaseId": null, + "sourceArtifact": "HelloService.postman.json", + "headers": [ + { + "name": "Content-Type", + "values": [ "application/json" ] + } + ], + "id": "65c6192bab2f0b1c5c395dd4", + "responseId": "65c6192bab2f0b1c5c395dd3", + "queryParameters": null + }, + { + "name": "Jane", + "content": "{\n \"firstname\" : \"Jane\",\n \"lastname\" : \"Smith\"\n}", + "operationId": "65c6170eab2f0b1c5c395dcc-greeting", + "testCaseId": null, + "sourceArtifact": "AI Copilot", + "headers": [], + "id": "65e5cee4c0b5876bb201a59a", + "responseId": "65e5cee4c0b5876bb201a599", + "queryParameters": null + }, + { + "name": "Andrew Request", + "content": "\n \n \n \n Andrew\n \n \n", + "operationId": "64c8deb82777ee53a545ca59-sayHello", + "testCaseId": null, + "sourceArtifact": "HelloService-soapui-project.xml", + "headers": null, + "id": "64c8deb82777ee53a545ca5d", + "responseId": "64c8deb82777ee53a545ca5c", + "queryParameters": null + }, + { + "name": "World Request", + "content": "\n \n \n \n\t World\n \n \n", + "operationId": "64c8deb82777ee53a545ca59-sayHello", + "testCaseId": null, + "sourceArtifact": "HelloService-soapui-project.xml", + "headers": null, + "id": "64c8deb82777ee53a545ca5f", + "responseId": "64c8deb82777ee53a545ca5e", + "queryParameters": null + }, + { + "name": "Karla Request", + "content": "\n \n \n \n\t\tKarla\n \n \n", + "operationId": "64c8deb82777ee53a545ca59-sayHello", + "testCaseId": null, + "sourceArtifact": "HelloService-soapui-project.xml", + "headers": null, + "id": "64c8deb82777ee53a545ca61", + "responseId": "64c8deb82777ee53a545ca60", + "queryParameters": null + }, + { + "name": "available response", + "content": null, + "operationId": "64b99e83e2dbae25009ded78-GET /v2/pet/findByStatus", + "testCaseId": null, + "sourceArtifact": "https://raw.githubusercontent.com/microcks/microcks/master/samples/PetstoreAPI-collection.json", + "headers": null, + "id": "6527f81898eb0d2f130f2b51", + "responseId": "6527f81898eb0d2f130f2b50", + "queryParameters": [ + { + "name": "user_key", + "value": "70f735676ec46351c6699c4bb767878a" + }, + { + "name": "status", + "value": "available" + } + ] + }, + { + "name": "available response", + "content": null, + "operationId": "64b99e83e2dbae25009ded78-GET /v2/pet/findByStatus", + "testCaseId": null, + "sourceArtifact": "PetstoreAPI-collection.json", + "headers": null, + "id": "6538d4aab525f9597c9de2f9", + "responseId": "6538d4aab525f9597c9de2f8", + "queryParameters": [ + { + "name": "user_key", + "value": "70f735676ec46351c6699c4bb767878a" + }, + { + "name": "status", + "value": "available" + } + ] + }, + { + "name": "get-1", + "content": null, + "operationId": "64b99e83e2dbae25009ded78-GET /v2/pet/:petId", + "testCaseId": null, + "sourceArtifact": "https://raw.githubusercontent.com/microcks/microcks/master/samples/PetstoreAPI-collection.json", + "headers": null, + "id": "6527f81898eb0d2f130f2b4d", + "responseId": "6527f81898eb0d2f130f2b4c", + "queryParameters": [ + { + "name": "petId", + "value": "1" + }, + { + "name": "user_key", + "value": "998bac0775b1d5f588e0a6ca7c11b852" + } + ] + }, + { + "name": "get-2", + "content": null, + "operationId": "64b99e83e2dbae25009ded78-GET /v2/pet/:petId", + "testCaseId": null, + "sourceArtifact": "https://raw.githubusercontent.com/microcks/microcks/master/samples/PetstoreAPI-collection.json", + "headers": null, + "id": "6527f81898eb0d2f130f2b4f", + "responseId": "6527f81898eb0d2f130f2b4e", + "queryParameters": [ + { + "name": "petId", + "value": "2" + }, + { + "name": "user_key", + "value": "70f735676ec46351c6699c4bb767878a" + } + ] + }, + { + "name": "get-1", + "content": null, + "operationId": "64b99e83e2dbae25009ded78-GET /v2/pet/:petId", + "testCaseId": null, + "sourceArtifact": "PetstoreAPI-collection.json", + "headers": null, + "id": "6538d4aab525f9597c9de2f5", + "responseId": "6538d4aab525f9597c9de2f4", + "queryParameters": [ + { + "name": "petId", + "value": "1" + }, + { + "name": "user_key", + "value": "998bac0775b1d5f588e0a6ca7c11b852" + } + ] + }, + { + "name": "get-2", + "content": null, + "operationId": "64b99e83e2dbae25009ded78-GET /v2/pet/:petId", + "testCaseId": null, + "sourceArtifact": "PetstoreAPI-collection.json", + "headers": null, + "id": "6538d4aab525f9597c9de2f7", + "responseId": "6538d4aab525f9597c9de2f6", + "queryParameters": [ + { + "name": "petId", + "value": "2" + }, + { + "name": "user_key", + "value": "70f735676ec46351c6699c4bb767878a" + } + ] + } + ], + "responses": [ + { + "name": "film ZmlsbXM6MQ==", + "content": "{\n \"data\": {\n \"film\": {\n \"id\": \"ZmlsbXM6MQ==\",\n \"title\": \"A New Hope\",\n \"episodeID\": 4,\n \"director\": \"George Lucas\",\n \"starCount\": 432,\n \"rating\": 4.3\n }\n }\n}", + "operationId": "65fd7a7a1f846c7939d014cf-film", + "testCaseId": null, + "sourceArtifact": "https://raw.githubusercontent.com/microcks/microcks/master/samples/films-postman.json", + "headers": null, + "id": "65fd7a7b1f846c7939d014d5", + "status": "200", + "mediaType": "application/json", + "dispatchCriteria": "?id=ZmlsbXM6MQ==", + "fault": false + }, + { + "name": "film ZmlsbXM6Mg==", + "content": "{\n \"data\": {\n \"film\": {\n \"id\": \"ZmlsbXM6Mg==\",\n \"title\": \"The Empire Strikes Back\",\n \"episodeID\": 5,\n \"director\": \"Irvin Kershner\",\n \"starCount\": 433,\n \"rating\": 4.3\n }\n }\n}", + "operationId": "65fd7a7a1f846c7939d014cf-film", + "testCaseId": null, + "sourceArtifact": "https://raw.githubusercontent.com/microcks/microcks/master/samples/films-postman.json", + "headers": null, + "id": "65fd7a7b1f846c7939d014d7", + "status": "200", + "mediaType": "application/json", + "dispatchCriteria": "?id=ZmlsbXM6Mg==", + "fault": false + }, + { + "name": "allFilms", + "content": "{\n \"data\": {\n \"allFilms\": {\n \"films\": [\n {\n \"id\": \"ZmlsbXM6MQ==\",\n \"title\": \"A New Hope\",\n \"episodeID\": 4,\n \"director\": \"George Lucas\",\n \"starCount\": 432,\n \"rating\": 4.3\n },\n {\n \"id\": \"ZmlsbXM6Mg==\",\n \"title\": \"The Empire Strikes Back\",\n \"episodeID\": 5,\n \"director\": \"Irvin Kershner\",\n \"starCount\": 433,\n \"rating\": 4.3\n },\n {\n \"id\": \"ZmlsbXM6Mw==\",\n \"title\": \"Return of the Jedi\",\n \"episodeID\": 6,\n \"director\": \"Richard Marquand\",\n \"starCount\": 434,\n \"rating\": 4.3\n },\n {\n \"id\": \"ZmlsbXM6NA==\",\n \"title\": \"The Phantom Menace\",\n \"episodeID\": 1,\n \"director\": \"George Lucas\",\n \"starCount\": 252,\n \"rating\": 3.2\n },\n {\n \"id\": \"ZmlsbXM6NQ==\",\n \"title\": \"Attack of the Clones\",\n \"episodeID\": 2,\n \"director\": \"George Lucas\",\n \"starCount\": 320,\n \"rating\": 3.9\n },\n {\n \"id\": \"ZmlsbXM6Ng==\",\n \"title\": \"Revenge of the Sith\",\n \"episodeID\": 3,\n \"director\": \"George Lucas\",\n \"starCount\": 410,\n \"rating\": 4.1\n }\n ]\n }\n }\n}", + "operationId": "65fd7a7a1f846c7939d014cf-allFilms", + "testCaseId": null, + "sourceArtifact": "https://raw.githubusercontent.com/microcks/microcks/master/samples/films-postman.json", + "headers": null, + "id": "65fd7a7b1f846c7939d014d3", + "status": "200", + "mediaType": "application/json", + "dispatchCriteria": null, + "fault": false + }, + { + "name": "addStar to ZmlsbXM6Mg==", + "content": "{\n \"data\": {\n \"addStar\": {\n \"id\": \"ZmlsbXM6Mg==\",\n \"title\": \"The Empire Strikes Back\",\n \"episodeID\": 5,\n \"director\": \"Irvin Kershner\",\n \"starCount\": 434,\n \"rating\": 4.3\n }\n }\n}", + "operationId": "65fd7a7a1f846c7939d014cf-addStar", + "testCaseId": null, + "sourceArtifact": "https://raw.githubusercontent.com/microcks/microcks/master/samples/films-postman.json", + "headers": null, + "id": "65fd7a7b1f846c7939d014d9", + "status": "200", + "mediaType": "application/json", + "dispatchCriteria": "?filmId=ZmlsbXM6Mg==", + "fault": false + }, + { + "name": "addReview to ZmlsbXM6Mg==", + "content": "{\n \"data\": {\n \"addReview\": {\n \"id\": \"ZmlsbXM6Mg==\",\n \"title\": \"The Empire Strikes Back\",\n \"episodeID\": 5,\n \"director\": \"Irvin Kershner\",\n \"starCount\": 433,\n \"rating\": 4.4\n }\n }\n}", + "operationId": "65fd7a7a1f846c7939d014cf-addReview", + "testCaseId": null, + "sourceArtifact": "https://raw.githubusercontent.com/microcks/microcks/master/samples/films-postman.json", + "headers": null, + "id": "65fd7a7b1f846c7939d014db", + "status": "200", + "mediaType": "application/json", + "dispatchCriteria": null, + "fault": false + }, + { + "name": "John", + "content": "{\n \"greeting\": \"Hello John Doe !\"\n}", + "operationId": "65c6170eab2f0b1c5c395dcc-greeting", + "testCaseId": null, + "sourceArtifact": "HelloService.postman.json", + "headers": null, + "id": "65c6192bab2f0b1c5c395dd1", + "status": "200", + "mediaType": "application/json", + "dispatchCriteria": null, + "fault": false + }, + { + "name": "Laurent", + "content": "{\n \"greeting\": \"Hello Laurent Broudoux !\"\n}", + "operationId": "65c6170eab2f0b1c5c395dcc-greeting", + "testCaseId": null, + "sourceArtifact": "HelloService.postman.json", + "headers": null, + "id": "65c6192bab2f0b1c5c395dd3", + "status": "200", + "mediaType": "application/json", + "dispatchCriteria": null, + "fault": false + }, + { + "name": "Jane", + "content": "{\n \"greeting\" : \"Hello, Jane Smith!\"\n}", + "operationId": "65c6170eab2f0b1c5c395dcc-greeting", + "testCaseId": null, + "sourceArtifact": "AI Copilot", + "headers": [], + "id": "65e5cee4c0b5876bb201a599", + "status": "200", + "mediaType": null, + "dispatchCriteria": null, + "fault": false + }, + { + "name": "Andrew Response", + "content": "\n \n \n \n Hello Andrew !\n \n \n", + "operationId": "64c8deb82777ee53a545ca59-sayHello", + "testCaseId": null, + "sourceArtifact": "HelloService-soapui-project.xml", + "headers": null, + "id": "64c8deb82777ee53a545ca5c", + "status": null, + "mediaType": null, + "dispatchCriteria": "Andrew Response", + "fault": false + }, + { + "name": "World Response", + "content": "\n \n \n \n \n soapenv:Sender\n \n rpc:BadArguments\n \n \n \n Processing error\n \n \n \n 999\n \n \n \n \n", + "operationId": "64c8deb82777ee53a545ca59-sayHello", + "testCaseId": null, + "sourceArtifact": "HelloService-soapui-project.xml", + "headers": null, + "id": "64c8deb82777ee53a545ca5e", + "status": null, + "mediaType": null, + "dispatchCriteria": "World Response", + "fault": true + }, + { + "name": "Karla Response", + "content": "\n \n \n \n Hello Karla !\n \n \n", + "operationId": "64c8deb82777ee53a545ca59-sayHello", + "testCaseId": null, + "sourceArtifact": "HelloService-soapui-project.xml", + "headers": null, + "id": "64c8deb82777ee53a545ca60", + "status": null, + "mediaType": null, + "dispatchCriteria": "Karla Response", + "fault": false + }, + { + "name": "available response", + "content": "[\n {\n \"id\": 190192062,\n \"category\": {\n \"id\": 0,\n \"name\": \"string\"\n },\n \"name\": \"doggie\",\n \"photoUrls\": [\n \"string\"\n ],\n \"tags\": [\n {\n \"id\": 0,\n \"name\": \"string\"\n }\n ],\n \"status\": \"available\"\n },\n {\n \"id\": 190192063,\n \"category\": {\n \"id\": 0,\n \"name\": \"string\"\n },\n \"name\": \"doggie\",\n \"photoUrls\": [\n \"string\"\n ],\n \"tags\": [\n {\n \"id\": 0,\n \"name\": \"string\"\n }\n ],\n \"status\": \"available\"\n },\n {\n \"id\": 190192285,\n \"category\": {\n \"id\": 0,\n \"name\": \"string\"\n },\n \"name\": \"doggie\",\n \"photoUrls\": [\n \"string\"\n ],\n \"tags\": [\n {\n \"id\": 0,\n \"name\": \"string\"\n }\n ],\n \"status\": \"available\"\n },\n {\n \"id\": 190192654,\n \"category\": {\n \"id\": 0,\n \"name\": \"string\"\n },\n \"name\": \"doggie\",\n \"photoUrls\": [\n \"string\"\n ],\n \"tags\": [\n {\n \"id\": 0,\n \"name\": \"string\"\n }\n ],\n \"status\": \"available\"\n },\n {\n \"id\": 190192671,\n \"category\": {\n \"id\": 0,\n \"name\": \"string\"\n },\n \"name\": \"doggie\",\n \"photoUrls\": [\n \"string\"\n ],\n \"tags\": [\n {\n \"id\": 0,\n \"name\": \"string\"\n }\n ],\n \"status\": \"available\"\n },\n {\n \"id\": 190192727,\n \"category\": {\n \"id\": 0,\n \"name\": \"string\"\n },\n \"name\": \"doggie\",\n \"photoUrls\": [\n \"string\"\n ],\n \"tags\": [\n {\n \"id\": 0,\n \"name\": \"string\"\n }\n ],\n \"status\": \"available\"\n },\n {\n \"id\": 190192736,\n \"category\": {\n \"id\": 0,\n \"name\": \"string\"\n },\n \"name\": \"doggie\",\n \"photoUrls\": [\n \"string\"\n ],\n \"tags\": [\n {\n \"id\": 0,\n \"name\": \"string\"\n }\n ],\n \"status\": \"available\"\n },\n {\n \"id\": 190192768,\n \"category\": {\n \"id\": 0,\n \"name\": \"string\"\n },\n \"name\": \"doggie\",\n \"photoUrls\": [\n \"string\"\n ],\n \"tags\": [\n {\n \"id\": 0,\n \"name\": \"string\"\n }\n ],\n \"status\": \"available\"\n },\n {\n \"id\": 190192878,\n \"category\": {\n \"id\": 0,\n \"name\": \"string\"\n },\n \"name\": \"doggie\",\n \"photoUrls\": [\n \"string\"\n ],\n \"tags\": [\n {\n \"id\": 0,\n \"name\": \"string\"\n }\n ],\n \"status\": \"available\"\n },\n {\n \"id\": 190192907,\n \"category\": {\n \"id\": 0,\n \"name\": \"string\"\n },\n \"name\": \"doggie\",\n \"photoUrls\": [\n \"string\"\n ],\n \"tags\": [\n {\n \"id\": 0,\n \"name\": \"string\"\n }\n ],\n \"status\": \"available\"\n },\n {\n \"id\": 190193000,\n \"category\": {\n \"id\": 0,\n \"name\": \"string\"\n },\n \"name\": \"doggie\",\n \"photoUrls\": [\n \"string\"\n ],\n \"tags\": [\n {\n \"id\": 0,\n \"name\": \"string\"\n }\n ],\n \"status\": \"available\"\n },\n {\n \"id\": -98125093,\n \"category\": {\n \"id\": -517488397,\n \"name\": \"EJvNbK\"\n },\n \"name\": \"LuEfMZATrHz\",\n \"photoUrls\": [\n \"XCXOVVkaxa\",\n \"gNwYqHEmC\",\n \"nvCvphDeuqztysUBNed\",\n \"W\",\n \"vmrxRIViyXqumolLIeoB\",\n \"JRqHVxk\",\n \"tCUGbegVHoXajm\",\n \"UiHppQn\"\n ],\n \"tags\": [\n {\n \"id\": 727599428,\n \"name\": \"RemggEDzxPljbrlktdWf\"\n },\n {\n \"id\": 1987753751,\n \"name\": \"zWqdKAGHMmhPPlomljaNtuvm\"\n },\n {\n \"id\": 1251632392,\n \"name\": \"BAgtgtKOxZGdsS\"\n },\n {\n \"id\": -1813025208,\n \"name\": \"OkKxtfAkCMEICbbQDVPi\"\n },\n {\n \"id\": -730110346,\n \"name\": \"WshDF\"\n },\n {\n \"id\": 2100951153,\n \"name\": \"yxUFSknQEleIAQCoocl\"\n },\n {\n \"id\": -2135188117,\n \"name\": \"M\"\n },\n {\n \"id\": 1352243140,\n \"name\": \"koKHsjysHXW\"\n },\n {\n \"id\": 1696778814,\n \"name\": \"KaihiyarcZkIzkkquWPZ\"\n },\n {\n \"id\": 659492963,\n \"name\": \"xqIzulcBPzWMyUpQwQK\"\n },\n {\n \"id\": -2118372841,\n \"name\": \"naYFGuHmqDqOpfHH\"\n }\n ],\n \"status\": \"available\"\n }\n]", + "operationId": "64b99e83e2dbae25009ded78-GET /v2/pet/findByStatus", + "testCaseId": null, + "sourceArtifact": "https://raw.githubusercontent.com/microcks/microcks/master/samples/PetstoreAPI-collection.json", + "headers": [ + { + "name": "Date", + "values": [ "Wed, 07 Dec 2016 15:31:45 GMT" ] + }, + { + "name": "X-Powered-By", + "values": [ "3scale API Management - http://www.3scale.net" ] + }, + { + "name": "Access-Control-Allow-Methods", + "values": [ "GET, POST, DELETE, PUT" ] + }, + { + "name": "Server", + "values": [ "openresty/1.9.15.1" ] + }, + { + "name": "Access-Control-Allow-Headers", + "values": [ "Content-Type, api_key, Authorization" ] + }, + { + "name": "Access-Control-Allow-Origin", + "values": [ "*" ] + }, + { + "name": "transfer-encoding", + "values": [ "chunked" ] + }, + { + "name": "Connection", + "values": [ "keep-alive" ] + }, + { + "name": "Content-Type", + "values": [ "application/json" ] + } + ], + "id": "6527f81898eb0d2f130f2b50", + "status": "200", + "mediaType": "application/json", + "dispatchCriteria": "?status=available?user_key=70f735676ec46351c6699c4bb767878a", + "fault": false + }, + { + "name": "available response", + "content": "[\n {\n \"id\": 190192062,\n \"category\": {\n \"id\": 0,\n \"name\": \"string\"\n },\n \"name\": \"doggie\",\n \"photoUrls\": [\n \"string\"\n ],\n \"tags\": [\n {\n \"id\": 0,\n \"name\": \"string\"\n }\n ],\n \"status\": \"available\"\n },\n {\n \"id\": 190192063,\n \"category\": {\n \"id\": 0,\n \"name\": \"string\"\n },\n \"name\": \"doggie\",\n \"photoUrls\": [\n \"string\"\n ],\n \"tags\": [\n {\n \"id\": 0,\n \"name\": \"string\"\n }\n ],\n \"status\": \"available\"\n },\n {\n \"id\": 190192285,\n \"category\": {\n \"id\": 0,\n \"name\": \"string\"\n },\n \"name\": \"doggie\",\n \"photoUrls\": [\n \"string\"\n ],\n \"tags\": [\n {\n \"id\": 0,\n \"name\": \"string\"\n }\n ],\n \"status\": \"available\"\n },\n {\n \"id\": 190192654,\n \"category\": {\n \"id\": 0,\n \"name\": \"string\"\n },\n \"name\": \"doggie\",\n \"photoUrls\": [\n \"string\"\n ],\n \"tags\": [\n {\n \"id\": 0,\n \"name\": \"string\"\n }\n ],\n \"status\": \"available\"\n },\n {\n \"id\": 190192671,\n \"category\": {\n \"id\": 0,\n \"name\": \"string\"\n },\n \"name\": \"doggie\",\n \"photoUrls\": [\n \"string\"\n ],\n \"tags\": [\n {\n \"id\": 0,\n \"name\": \"string\"\n }\n ],\n \"status\": \"available\"\n },\n {\n \"id\": 190192727,\n \"category\": {\n \"id\": 0,\n \"name\": \"string\"\n },\n \"name\": \"doggie\",\n \"photoUrls\": [\n \"string\"\n ],\n \"tags\": [\n {\n \"id\": 0,\n \"name\": \"string\"\n }\n ],\n \"status\": \"available\"\n },\n {\n \"id\": 190192736,\n \"category\": {\n \"id\": 0,\n \"name\": \"string\"\n },\n \"name\": \"doggie\",\n \"photoUrls\": [\n \"string\"\n ],\n \"tags\": [\n {\n \"id\": 0,\n \"name\": \"string\"\n }\n ],\n \"status\": \"available\"\n },\n {\n \"id\": 190192768,\n \"category\": {\n \"id\": 0,\n \"name\": \"string\"\n },\n \"name\": \"doggie\",\n \"photoUrls\": [\n \"string\"\n ],\n \"tags\": [\n {\n \"id\": 0,\n \"name\": \"string\"\n }\n ],\n \"status\": \"available\"\n },\n {\n \"id\": 190192878,\n \"category\": {\n \"id\": 0,\n \"name\": \"string\"\n },\n \"name\": \"doggie\",\n \"photoUrls\": [\n \"string\"\n ],\n \"tags\": [\n {\n \"id\": 0,\n \"name\": \"string\"\n }\n ],\n \"status\": \"available\"\n },\n {\n \"id\": 190192907,\n \"category\": {\n \"id\": 0,\n \"name\": \"string\"\n },\n \"name\": \"doggie\",\n \"photoUrls\": [\n \"string\"\n ],\n \"tags\": [\n {\n \"id\": 0,\n \"name\": \"string\"\n }\n ],\n \"status\": \"available\"\n },\n {\n \"id\": 190193000,\n \"category\": {\n \"id\": 0,\n \"name\": \"string\"\n },\n \"name\": \"doggie\",\n \"photoUrls\": [\n \"string\"\n ],\n \"tags\": [\n {\n \"id\": 0,\n \"name\": \"string\"\n }\n ],\n \"status\": \"available\"\n },\n {\n \"id\": -98125093,\n \"category\": {\n \"id\": -517488397,\n \"name\": \"EJvNbK\"\n },\n \"name\": \"LuEfMZATrHz\",\n \"photoUrls\": [\n \"XCXOVVkaxa\",\n \"gNwYqHEmC\",\n \"nvCvphDeuqztysUBNed\",\n \"W\",\n \"vmrxRIViyXqumolLIeoB\",\n \"JRqHVxk\",\n \"tCUGbegVHoXajm\",\n \"UiHppQn\"\n ],\n \"tags\": [\n {\n \"id\": 727599428,\n \"name\": \"RemggEDzxPljbrlktdWf\"\n },\n {\n \"id\": 1987753751,\n \"name\": \"zWqdKAGHMmhPPlomljaNtuvm\"\n },\n {\n \"id\": 1251632392,\n \"name\": \"BAgtgtKOxZGdsS\"\n },\n {\n \"id\": -1813025208,\n \"name\": \"OkKxtfAkCMEICbbQDVPi\"\n },\n {\n \"id\": -730110346,\n \"name\": \"WshDF\"\n },\n {\n \"id\": 2100951153,\n \"name\": \"yxUFSknQEleIAQCoocl\"\n },\n {\n \"id\": -2135188117,\n \"name\": \"M\"\n },\n {\n \"id\": 1352243140,\n \"name\": \"koKHsjysHXW\"\n },\n {\n \"id\": 1696778814,\n \"name\": \"KaihiyarcZkIzkkquWPZ\"\n },\n {\n \"id\": 659492963,\n \"name\": \"xqIzulcBPzWMyUpQwQK\"\n },\n {\n \"id\": -2118372841,\n \"name\": \"naYFGuHmqDqOpfHH\"\n }\n ],\n \"status\": \"available\"\n }\n]", + "operationId": "64b99e83e2dbae25009ded78-GET /v2/pet/findByStatus", + "testCaseId": null, + "sourceArtifact": "PetstoreAPI-collection.json", + "headers": [ + { + "name": "Access-Control-Allow-Headers", + "values": [ "Content-Type, api_key, Authorization" ] + }, + { + "name": "Server", + "values": [ "openresty/1.9.15.1" ] + }, + { + "name": "Access-Control-Allow-Origin", + "values": [ "*" ] + }, + { + "name": "Date", + "values": [ "Wed, 07 Dec 2016 15:31:45 GMT" ] + }, + { + "name": "Access-Control-Allow-Methods", + "values": [ "GET, POST, DELETE, PUT" ] + }, + { + "name": "Connection", + "values": [ "keep-alive" ] + }, + { + "name": "Content-Type", + "values": [ "application/json" ] + }, + { + "name": "X-Powered-By", + "values": [ "3scale API Management - http://www.3scale.net" ] + }, + { + "name": "transfer-encoding", + "values": [ "chunked" ] + } + ], + "id": "6538d4aab525f9597c9de2f8", + "status": "200", + "mediaType": "application/json", + "dispatchCriteria": "?status=available?user_key=70f735676ec46351c6699c4bb767878a", + "fault": false + }, + { + "name": "get-1", + "content": "", + "operationId": "64b99e83e2dbae25009ded78-GET /v2/pet/:petId", + "testCaseId": null, + "sourceArtifact": "https://raw.githubusercontent.com/microcks/microcks/master/samples/PetstoreAPI-collection.json", + "headers": [ + { + "name": "X-Powered-By", + "values": [ "3scale API Management - http://www.3scale.net" ] + }, + { + "name": "Content-Type", + "values": [ "application/json" ] + }, + { + "name": "Access-Control-Allow-Origin", + "values": [ "*" ] + }, + { + "name": "Server", + "values": [ "openresty/1.9.7.4" ] + }, + { + "name": "Date", + "values": [ "Wed, 07 Dec 2016 15:27:22 GMT" ] + }, + { + "name": "Access-Control-Allow-Headers", + "values": [ "Content-Type, api_key, Authorization" ] + }, + { + "name": "Access-Control-Allow-Methods", + "values": [ "GET, POST, DELETE, PUT" ] + }, + { + "name": "Content-Length", + "values": [ "0" ] + }, + { + "name": "Connection", + "values": [ "keep-alive" ] + } + ], + "id": "6527f81898eb0d2f130f2b4c", + "status": "404", + "mediaType": "application/json", + "dispatchCriteria": null, + "fault": false + }, + { + "name": "get-2", + "content": "{\"id\":2,\"category\":{\"id\":1,\"name\":\"Animal\"},\"name\":\"cat\",\"photoUrls\":[\"string\"],\"tags\":[{\"id\":1,\"name\":\"domestic\"}],\"status\":\"available\"}", + "operationId": "64b99e83e2dbae25009ded78-GET /v2/pet/:petId", + "testCaseId": null, + "sourceArtifact": "https://raw.githubusercontent.com/microcks/microcks/master/samples/PetstoreAPI-collection.json", + "headers": [ + { + "name": "Content-Length", + "values": [ "137" ] + }, + { + "name": "Connection", + "values": [ "keep-alive" ] + }, + { + "name": "X-Powered-By", + "values": [ "3scale API Management - http://www.3scale.net" ] + }, + { + "name": "Date", + "values": [ "Wed, 07 Dec 2016 15:27:18 GMT" ] + }, + { + "name": "Content-Type", + "values": [ "application/json" ] + }, + { + "name": "Access-Control-Allow-Methods", + "values": [ "GET, POST, DELETE, PUT" ] + }, + { + "name": "Server", + "values": [ "openresty/1.9.7.4" ] + }, + { + "name": "Access-Control-Allow-Headers", + "values": [ "Content-Type, api_key, Authorization" ] + }, + { + "name": "Access-Control-Allow-Origin", + "values": [ "*" ] + } + ], + "id": "6527f81898eb0d2f130f2b4e", + "status": "200", + "mediaType": "application/json", + "dispatchCriteria": null, + "fault": false + }, + { + "name": "get-1", + "content": "", + "operationId": "64b99e83e2dbae25009ded78-GET /v2/pet/:petId", + "testCaseId": null, + "sourceArtifact": "PetstoreAPI-collection.json", + "headers": [ + { + "name": "Access-Control-Allow-Origin", + "values": [ "*" ] + }, + { + "name": "Access-Control-Allow-Methods", + "values": [ "GET, POST, DELETE, PUT" ] + }, + { + "name": "Access-Control-Allow-Headers", + "values": [ "Content-Type, api_key, Authorization" ] + }, + { + "name": "Content-Type", + "values": [ "application/json" ] + }, + { + "name": "Content-Length", + "values": [ "0" ] + }, + { + "name": "X-Powered-By", + "values": [ "3scale API Management - http://www.3scale.net" ] + }, + { + "name": "Server", + "values": [ "openresty/1.9.7.4" ] + }, + { + "name": "Connection", + "values": [ "keep-alive" ] + }, + { + "name": "Date", + "values": [ "Wed, 07 Dec 2016 15:27:22 GMT" ] + } + ], + "id": "6538d4aab525f9597c9de2f4", + "status": "404", + "mediaType": "application/json", + "dispatchCriteria": null, + "fault": false + }, + { + "name": "get-2", + "content": "{\"id\":2,\"category\":{\"id\":1,\"name\":\"Animal\"},\"name\":\"cat\",\"photoUrls\":[\"string\"],\"tags\":[{\"id\":1,\"name\":\"domestic\"}],\"status\":\"available\"}", + "operationId": "64b99e83e2dbae25009ded78-GET /v2/pet/:petId", + "testCaseId": null, + "sourceArtifact": "PetstoreAPI-collection.json", + "headers": [ + { + "name": "Content-Type", + "values": [ "application/json" ] + }, + { + "name": "Content-Length", + "values": [ "137" ] + }, + { + "name": "X-Powered-By", + "values": [ "3scale API Management - http://www.3scale.net" ] + }, + { + "name": "Server", + "values": [ "openresty/1.9.7.4" ] + }, + { + "name": "Connection", + "values": [ "keep-alive" ] + }, + { + "name": "Access-Control-Allow-Methods", + "values": [ "GET, POST, DELETE, PUT" ] + }, + { + "name": "Access-Control-Allow-Headers", + "values": [ "Content-Type, api_key, Authorization" ] + }, + { + "name": "Access-Control-Allow-Origin", + "values": [ "*" ] + }, + { + "name": "Date", + "values": [ "Wed, 07 Dec 2016 15:27:18 GMT" ] + } + ], + "id": "6538d4aab525f9597c9de2f6", + "status": "200", + "mediaType": "application/json", + "dispatchCriteria": null, + "fault": false + } + ], + "eventMessages": [] +} diff --git a/tests/Microcks.Testcontainers.Tests/subdir/weather-forecast-openapi.yaml b/tests/Microcks.Testcontainers.Tests/subdir/weather-forecast-openapi.yaml new file mode 100644 index 0000000..c4ba4e3 --- /dev/null +++ b/tests/Microcks.Testcontainers.Tests/subdir/weather-forecast-openapi.yaml @@ -0,0 +1,100 @@ +--- +openapi: 3.0.2 +info: + title: WeatherForecast API + version: 1.0.0 + description: A simple API for demonstrating dispatching capabilities in Microcks + contact: + name: Laurent Broudoux + url: https://github.com/lbroudoux + email: laurent.broudoux@gmail.com + license: + name: MIT License + url: https://opensource.org/licenses/MIT +paths: + /forecast/{region}: + get: + operationId: GetForecast + summary: Get forecast for region + description: Get forecast for region + tags: + - forecast + parameters: + - name: region + description: The region to get forecast for + schema: + type: string + in: path + required: true + examples: + unknown: + value: other + north: + value: north + west: + value: west + east: + value: east + south: + value: south + - name: apiKey + description: Client API key + schema: + type: string + in: query + required: true + responses: + "200": + description: Weather forecast for region + content: + application/json: + schema: + type: object + properties: + region: + type: string + temp: + format: double + type: number + weather: + type: string + visibility: + format: int32 + type: integer + examples: + north: + value: + region: north + temp: -1.5 + weather: snowy + visibility: 25 + west: + value: + region: west + temp: 12.2 + weather: rainy + visibility: 300 + east: + value: + region: east + temp: -6.6 + weather: frosty + visibility: 523 + south: + value: + region: south + temp: 28.3 + weather: sunny + visibility: 1500 + "404": + description: Region is unknown + content: + application/json: + schema: + type: string + examples: + unknown: + value: "Region is unknown. Choose in north, west, east or south." +tags: + - name: forecast + description: Foreacast related operation