Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 3 additions & 1 deletion .github/dependabot.yml
Original file line number Diff line number Diff line change
Expand Up @@ -49,7 +49,9 @@ updates:
patterns:
- "*kiota*"
- package-ecosystem: composer
directory: "/it/php"
directories:
- "/it/php"
- "/it/php/basic"
schedule:
interval: daily
open-pull-requests-limit: 10
Expand Down
1 change: 1 addition & 0 deletions .github/workflows/integration-tests.yml
Original file line number Diff line number Diff line change
Expand Up @@ -90,6 +90,7 @@ jobs:
- "./tests/Kiota.Builder.IntegrationTests/ToDoApi.yaml"
- "./tests/Kiota.Builder.IntegrationTests/GeneratesUritemplateHints.yaml"
- "./tests/Kiota.Builder.IntegrationTests/DiscriminatorSample.yaml"
- "./tests/Kiota.Builder.IntegrationTests/ModelWithDefaultValues.json"
- "oas::petstore"
- "apisguru::twitter.com:current"
- "apisguru::notion.com"
Expand Down
1 change: 1 addition & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -451,6 +451,7 @@ reports/

samples/
it/openapi.yaml
it/openapi.json

idempotency-results/
vscode/npm-package/dist/*
Expand Down
2 changes: 2 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,8 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0

### Changed

- C#, Java, Go, PHP, Dart, TypeScript, Python and Ruby client: default value initialization in model classes for DateTime/Date/Time/UUID properties did not compile [#7404](https://github.com/microsoft/kiota/issues/7404)
- All languages: default value initialization in model classes for numeric/boolean properties was missing [#7404](https://github.com/microsoft/kiota/issues/7404)
- Fixed a potential NullReferenceException in union model discriminator factory methods when a discriminator mapping key is null or empty across C#, Dart, Go, Java, PHP, and Python writers. [#7641](https://github.com/microsoft/kiota/pull/7641)
- Fixed `kiota download` returning exit code 0 (success) when no results are found or multiple ambiguous matches exist. [#7643](https://github.com/microsoft/kiota/pull/7643)
- Fixed incorrect command hints and telemetry in `kiota plugin generate` handler referencing "client" instead of "plugin". [#7642](https://github.com/microsoft/kiota/pull/7642)
Expand Down
45 changes: 45 additions & 0 deletions it/Readme.md
Original file line number Diff line number Diff line change
Expand Up @@ -19,3 +19,48 @@ And finally run the test:
```bash
./it/exec-cmd.ps1 -descriptionUrl ${FILE/URL} -language ${LANG}
```

# MockServer tests

The OpenAPI description can be published to a mock server, and you can execute tests that call this API.

To do so, first define a "MockServerITFolder" property in "config.json"

```
"./tests/Kiota.Builder.IntegrationTests/MySampleAPI.yml": {
"MockServerITFolder": "mysample"
},
```

When calling "exec-cmd.ps1" for a specific language, the scripts checks whether this sub folder exists in
the directory corresponding to the language.
If it exists, it executes the tests found in this directory.

The handling depends on the language:

* C#: place the tests in "it\csharp\mysample". Use the test class "basic\KiotaMockServerTests.cs" as a test file template.
The subdir should also contain a project file and maybe "Usings.cs" if your test class relies on global usings.
But you can use the default files: if "exec-cmd.ps1" finds no csproj file in the subdir, it copies "basic\basic.csproj" to
your test subdir and removes it afterwards. The same is done for "Usings.cs"
* Dart: place the tests in "it\dart\mysample\test". Use the test class "it\dart\basic\test\api_client_test.dart" as a test file template.
No additional files are required.
* Go: place the tests in "it\go\mysample". Use the test class "it\go\basic\client_test.go" as a test file template.
The subdir should also contain "go.mod" and "go.sum".
But you can use the default files: if "exec-cmd.ps1" does not find them in the subdir, it copies them from the "basic" dir to
your test subdir and removes them afterwards.
* Java: place the tests in "it\java\mysample\src\test\java". Use the test class "it\java\basic\src\test\java\BasicAPITest.java" as a test file template.
The subdir should also contain "pom.xml".
But you can use the default file: if "exec-cmd.ps1" does not find it in the subdir, it copies it from the "basic" dir to
your test subdir and removes it afterwards.
* PHP: place the tests in "it\php\mysample\tests". Use the test class "it\php\basic\tests\SampleTest.php" as a test file template.
The subdir should also contain "composer.json" and "phpstan.neon".
But you can use the default files: if "exec-cmd.ps1" does not find them in the subdir, it copies them from the "basic" dir to
your test subdir and removes them afterwards.
* Python: place the tests in "it\python\mysample". Use the test class "it\python\basic\test_sample.py" as a test file template.
No additional files are required.
* Ruby: place the tests in "it\ruby\spec\mysample" (difference to other tests!). Use the test class "it\ruby\spec\defaultvalues\integration_test_defaultvalues.rb" as a test file template.
No additional files are required.
* Typescript: not supported.

If you create e.g. a custom "csproj" file for your test (might be necessary if you need additional dependencies), add this file
to the Dependabot config so that dependencies are updated.
11 changes: 11 additions & 0 deletions it/config.json
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,9 @@
}
]
},
"./tests/Kiota.Builder.IntegrationTests/ModelWithDefaultValues.json": {
"MockServerITFolder": "defaultvalues"
},
"apisguru::github.com:api.github.com": {
"MockServerITFolder": "gh",
"Suppressions": [
Expand All @@ -46,6 +49,14 @@
{
"Pattern": "/user/gpg_keys/**",
"Rationale": "https://github.com/github/rest-api-description/issues/2247"
},
{
"Pattern": "/repos/{owner}/{repo}/releases/{release_id}#PATCH",
"Rationale": "https://github.com/microsoft/kiota/pull/7414#issuecomment-4033965839 and https://github.com/github/rest-api-description/issues/6100 (default value for enum is not quoted)"
},
{
"Pattern": "/repos/{owner}/{repo}/releases#POST",
"Rationale": "https://github.com/microsoft/kiota/pull/7414#issuecomment-4033965839 (default value for enum is not quoted, fixed in recent file as of 03/2026 but not updated to APIGurus)"
}
]
},
Expand Down
3 changes: 3 additions & 0 deletions it/csharp/.gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,9 @@
##
## Get latest from https://github.com/github/gitignore/blob/main/VisualStudio.gitignore

#generated api code if integration test is run locally
client/

# User-specific files
*.rsuser
*.suo
Expand Down
50 changes: 50 additions & 0 deletions it/csharp/defaultvalues/KiotaMockServerTests.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,50 @@
using App.Client;
using Microsoft.Kiota.Http.HttpClientLibrary;
using Microsoft.Kiota.Abstractions.Authentication;
using App.Client.Models;

namespace Kiota.IT.MockServerTests;
public class KiotaMockServerTests
{
/// <summary>
/// Tests that default values of a model class are applied when creating a new instance.
/// </summary>
[Fact]
public async Task DefaultValuesInModelClassTest()
{
var requestAdapter = new HttpClientRequestAdapter(new AnonymousAuthenticationProvider());
requestAdapter.BaseUrl = "http://localhost:1080";
var client = new ApiClient(requestAdapter);

//Call a sample endpoint - not really needed here.
List<WeatherForecast>? modelList = await client.Api.V1.WeatherForecast.GetAsync(cancellationToken: TestContext.Current.CancellationToken);
Assert.NotNull(modelList);
Assert.Single(modelList);

//Now the real test: create a model class and verify that all properties have the default values.
WeatherForecast model = new WeatherForecast();
Assert.True(model.BoolValue);

Assert.NotNull(model.DateOnlyValue);
Assert.Equal("1900-01-01", model.DateOnlyValue.Value.ToString());

Assert.NotNull(model.DateValue);
Assert.Equal("1900-01-01 00:00", model.DateValue.Value.ToString("yyyy-MM-dd HH:mm"));

Assert.Equal(25.5, model.DecimalValue);
Assert.Equal(25.5, model.DoubleValue);
Assert.Equal(WeatherForecast_enumValue.One, model.EnumValue);
Assert.Equal(25.5f, model.FloatValue);

Assert.NotNull(model.GuidValue);
Assert.Equal("00000000-0000-0000-0000-000000000000", model.GuidValue.Value.ToString());

Assert.Equal(255, model.LongValue);
Assert.Equal("Test", model.Summary);
Assert.Equal(15, model.TemperatureC);

Assert.NotNull(model.TimeValue);
Assert.Equal("00:00:00", model.TimeValue.Value.ToString());

}
}
2 changes: 2 additions & 0 deletions it/csharp/dotnet.csproj
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,9 @@
<PackageReference Include="Microsoft.kiota.Serialization.Multipart" Version="1.22.1" />
<PackageReference Include="Microsoft.Kiota.Serialization.Text" Version="1.22.1" />

<!-- Exclude code from subprojects, that might be used for MockServer tests -->
<Compile Remove="basic\**" />
<Compile Remove="defaultvalues\**" />
</ItemGroup>

</Project>
5 changes: 4 additions & 1 deletion it/dart/.gitignore
Original file line number Diff line number Diff line change
@@ -1,3 +1,6 @@
pubspec.lock
.dart_tool/
src/
src/

#generated api code if integration test is run locally
lib/
56 changes: 56 additions & 0 deletions it/dart/defaultvalues/test/api_client_test.dart
Original file line number Diff line number Diff line change
@@ -0,0 +1,56 @@
import 'package:microsoft_kiota_abstractions/microsoft_kiota_abstractions.dart';
import 'package:microsoft_kiota_http/microsoft_kiota_http.dart';
import 'package:test/test.dart';
import '../lib/api_client.dart';
import '../lib/models/weather_forecast.dart';
import '../lib/models/weather_forecast_enum_value.dart';

void main() {
group('apiclient', () {
test('basic endpoint test', () async {
final requestAdapter = HttpClientRequestAdapter(
client: KiotaClientFactory.createClient(),
authProvider: AnonymousAuthenticationProvider(),
pNodeFactory: ParseNodeFactoryRegistry.defaultInstance,
sWriterFactory: SerializationWriterFactoryRegistry.defaultInstance,
);
requestAdapter.baseUrl = "http://localhost:1080";
var client = ApiClient(requestAdapter);

//Call a sample endpoint - not really needed here.
var serviceResponse = await client.api.v1.weatherForecast.getAsync();
expect(serviceResponse, isNotNull);
expect(serviceResponse?.length, 1);

//Now the real test: create a model class and verify that all properties have the default values.
var model = new WeatherForecast();
expect(true, model.boolValue);

expect(model.dateOnlyValue, isNotNull);
expect(model.dateOnlyValue!.toRfc3339String(), "1900-01-01"); //from DateOnlyExtensions

expect(model.dateValue, isNotNull);
//default format: the timezone is "Z".
expect(model.dateValue!.toString(), "1900-01-01 00:00:00.000Z");

expect(model.dateValueLocalTime, isNotNull);
//default format: no timezone.
expect(model.dateValueLocalTime!.toString(), "1900-01-01 00:00:00.000");

expect(model.decimalValue!, 25.5);
expect(model.doubleValue!, 25.5);
expect(model.enumValue!, WeatherForecastEnumValue.one);
expect(model.floatValue!, 25.5);

expect(model.guidValue, isNotNull);
expect(model.guidValue!.toString(), "00000000-0000-0000-0000-000000000000");

expect(model.longValue!, 255);
expect(model.summary!, "Test");
expect(model.temperatureC!, 15);

expect(model.timeValue, isNotNull);
expect(model.timeValue!.toRfc3339String(), "00:00:00"); //from TimeOnlyExtensions. Millis are only printed if not "0"
});
});
}
8 changes: 7 additions & 1 deletion it/download-openapi-specs.ps1
Original file line number Diff line number Diff line change
Expand Up @@ -30,7 +30,13 @@ switch ($dev) {
}
}

$targetOpenapiPath = Join-Path -Path $PSScriptRoot -ChildPath "openapi.yaml"
#api description might be a JSON or a yaml file (or a apigurus name, which is hopefully a json file).
if ($descriptionUrl.ToLower().EndsWith(".json")) {
$targetOpenapiPath = Join-Path -Path $PSScriptRoot -ChildPath "openapi.json"
}
else {
$targetOpenapiPath = Join-Path -Path $PSScriptRoot -ChildPath "openapi.yaml"
}
if (Test-Path $targetOpenapiPath) {
Remove-Item $targetOpenapiPath
}
Expand Down
Loading