Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

add ApiPlcProgramBlockType enum #44

Merged
merged 1 commit into from
Dec 4, 2023
Merged
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
5 changes: 1 addition & 4 deletions src/Webserver.API/Enums/ApiErrorCode.cs
Original file line number Diff line number Diff line change
Expand Up @@ -235,8 +235,5 @@ public enum ApiErrorCode
/// Invalid Parameters provided (null/empty string that is forbidden?, invalid ticket length?, wrong datetime string format (rfc3339)? ...)
/// </summary>
InvalidParams = -32602



}
}
}
47 changes: 47 additions & 0 deletions src/Webserver.API/Enums/ApiPlcProgramBlockType.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,47 @@
// Copyright (c) 2023, Siemens AG
//
// SPDX-License-Identifier: MIT

using Newtonsoft.Json;
using Newtonsoft.Json.Converters;
using System.Runtime.Serialization;

namespace Siemens.Simatic.S7.Webserver.API.Enums
{
/// <summary>
/// Block type enumeration.
/// </summary>
[JsonConverter(typeof(StringEnumConverter))]
public enum ApiPlcProgramBlockType
{
/// <summary>
/// OB block.
/// </summary>
[EnumMember(Value = "ob")]
Ob,

/// <summary>
/// FB block.
/// </summary>
[EnumMember(Value = "fc")]
Fc,

/// <summary>
/// FC block.
/// </summary>
[EnumMember(Value = "fb")]
Fb,

/// <summary>
/// SFB block.
/// </summary>
[EnumMember(Value = "sfc")]
Sfc,

/// <summary>
/// SFC block.
/// </summary>
[EnumMember(Value = "sfb")]
Sfb,
}
}
7 changes: 4 additions & 3 deletions src/Webserver.API/Models/ApiPlcProgramBrowseCodeBlocksData.cs
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@
// SPDX-License-Identifier: MIT
using Newtonsoft.Json;
using Newtonsoft.Json.Serialization;
using Siemens.Simatic.S7.Webserver.API.Enums;
using System;

namespace Siemens.Simatic.S7.Webserver.API.Models
Expand All @@ -18,7 +19,7 @@ public class ApiPlcProgramBrowseCodeBlocksData : IEquatable<ApiPlcProgramBrowseC
/// <returns></returns>
public ApiPlcProgramBrowseCodeBlocksData ShallowCopy()
{
return (ApiPlcProgramBrowseCodeBlocksData) this.MemberwiseClone();
return (ApiPlcProgramBrowseCodeBlocksData)this.MemberwiseClone();
}

/// <summary>
Expand All @@ -37,13 +38,13 @@ public ApiPlcProgramBrowseCodeBlocksData ShallowCopy()
/// Type of the code block.
/// </summary>
[JsonProperty("block_type")]
public string BlockType { get; set; }
public ApiPlcProgramBlockType BlockType { get; set; }

/// <summary>
/// Constructor.
/// </summary>
[JsonConstructor]
public ApiPlcProgramBrowseCodeBlocksData(string name, ushort blockNumber, string blockType)
public ApiPlcProgramBrowseCodeBlocksData(string name, ushort blockNumber, ApiPlcProgramBlockType blockType)
{
Name = name;
BlockNumber = blockNumber;
Expand Down
206 changes: 205 additions & 1 deletion tests/Webserver.API.UnitTests/ApiRequestTests.cs
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,6 @@
using Siemens.Simatic.S7.Webserver.API.Enums;
using Siemens.Simatic.S7.Webserver.API.Exceptions;
using Siemens.Simatic.S7.Webserver.API.Models;
using Siemens.Simatic.S7.Webserver.API.Models.ApiDiagnosticBuffer;
using Siemens.Simatic.S7.Webserver.API.Models.FailsafeParameters;
using Siemens.Simatic.S7.Webserver.API.Models.Requests;
using Siemens.Simatic.S7.Webserver.API.Models.Responses;
Expand Down Expand Up @@ -1075,6 +1074,69 @@ public void T013_06_ApiPlcProgramBrowse_InvalidArrayIndex_ExcThrown()
Assert.ThrowsAsync<ApiInvalidArrayIndexException>(async () => await TestHandler.PlcProgramBrowseAsync(ApiPlcProgramBrowseMode.Children, "\"DataTypes\".\"Bool\"a"));
}

/// <summary>
///
/// </summary>
/// <returns></returns>
[Test]
public async Task T014_01_PlcProgramDownloadProfilingData_Success()
{
var mockHttp = new MockHttpMessageHandler();
// Setup a respond for the user api (including a wildcard in the URL)
mockHttp.When(HttpMethod.Post, $"https://{Ip.ToString()}/api/jsonrpc")
.Respond("application/json", ResponseStrings.PlcProgramDownloadProfilingDataSuccess); // Respond with JSON
// Inject the handler or client into your application code
var client = new HttpClient(mockHttp);
client.BaseAddress = new Uri($"https://{Ip.ToString()}");
TestHandler = new ApiHttpClientRequestHandler(client, ApiRequestFactory, ApiResponseChecker);

ApiSingleStringResponse response = await TestHandler.PlcProgramDownloadProfilingDataAsync();

Assert.That(response.Result.Equals("jgxikeMgLryvP0YoHc.eqt8BY787"));
}

/// <summary>
///
/// </summary>
/// <returns></returns>
[Test]
public void T014_02_PlcProgramDownloadProfilingData_NoResources()
{
// This case could happen if the user downloads the profiling
// data twice without clearing the ticket or downloading the actual data.

var mockHttp = new MockHttpMessageHandler();
// Setup a respond for the user api (including a wildcard in the URL)
mockHttp.When(HttpMethod.Post, $"https://{Ip.ToString()}/api/jsonrpc")
.Respond("application/json", ResponseStrings.PlcProgramDownloadProfilingDataNoResources); // Respond with JSON
// Inject the handler or client into your application code
var client = new HttpClient(mockHttp);
client.BaseAddress = new Uri($"https://{Ip.ToString()}");
TestHandler = new ApiHttpClientRequestHandler(client, ApiRequestFactory, ApiResponseChecker);

Assert.ThrowsAsync<ApiNoResourcesException>(async () => await TestHandler.PlcProgramDownloadProfilingDataAsync());
}

/// <summary>
///
/// </summary>
/// <returns></returns>
[Test]
public void T014_03_PlcProgramDownloadProfilingData_PermissionDenied()
{

var mockHttp = new MockHttpMessageHandler();
// Setup a respond for the user api (including a wildcard in the URL)
mockHttp.When(HttpMethod.Post, $"https://{Ip.ToString()}/api/jsonrpc")
.Respond("application/json", ResponseStrings.PlcProgramDownloadProfilingDataPermissionDenied); // Respond with JSON
// Inject the handler or client into your application code
var client = new HttpClient(mockHttp);
client.BaseAddress = new Uri($"https://{Ip.ToString()}");
TestHandler = new ApiHttpClientRequestHandler(client, ApiRequestFactory, ApiResponseChecker);

Assert.ThrowsAsync<System.UnauthorizedAccessException>(async () => await TestHandler.PlcProgramDownloadProfilingDataAsync());
}

/// <summary>
///
/// </summary>
Expand All @@ -1093,6 +1155,148 @@ public void T015_ApiPlcProgramBrowse_PermissionDenied_ExcThrown()
Assert.ThrowsAsync<UnauthorizedAccessException>(async () => await TestHandler.PlcProgramBrowseAsync(ApiPlcProgramBrowseMode.Children, "\"DataTypes\".\"Bool\""));
}

/// <summary>
///
/// </summary>
/// <returns></returns>
[Test]
public async Task T015_02_ApiPlcProgramBrowseCodeBlocks_EmptyResult()
{
var mockHttp = new MockHttpMessageHandler();
// Setup a respond for the user api (including a wildcard in the URL)
mockHttp.When(HttpMethod.Post, $"https://{Ip.ToString()}/api/jsonrpc")
.Respond("application/json", ResponseStrings.PlcProgramBrowseCodeBlocksEmptyResult); // Respond with JSON
// Inject the handler or client into your application code
var client = new HttpClient(mockHttp);
client.BaseAddress = new Uri($"https://{Ip.ToString()}");
TestHandler = new ApiHttpClientRequestHandler(client, ApiRequestFactory, ApiResponseChecker);

ApiPlcProgramBrowseCodeBlocksResponse response = await TestHandler.PlcProgramBrowseCodeBlocksAsync();
Assert.That(response.Result.Count == 0);
}

/// <summary>
///
/// </summary>
/// <returns></returns>
[Test]
public void T015_03_ApiPlcProgramBrowseCodeBlocks_InvalidParams()
{
var mockHttp = new MockHttpMessageHandler();
// Setup a respond for the user api (including a wildcard in the URL)
mockHttp.When(HttpMethod.Post, $"https://{Ip.ToString()}/api/jsonrpc")
.Respond("application/json", ResponseStrings.PlcProgramBrowseCodeBlocksInvalidParams); // Respond with JSON
// Inject the handler or client into your application code
var client = new HttpClient(mockHttp);
client.BaseAddress = new Uri($"https://{Ip.ToString()}");
TestHandler = new ApiHttpClientRequestHandler(client, ApiRequestFactory, ApiResponseChecker);

Assert.ThrowsAsync<ApiInvalidParametersException>(async () => await TestHandler.PlcProgramBrowseCodeBlocksAsync());
}

/// <summary>
///
/// </summary>
/// <returns></returns>
[Test]
public async Task T015_04_ApiPlcProgramBrowseCodeBlocks_Success()
{
var mockHttp = new MockHttpMessageHandler();
// Setup a respond for the user api (including a wildcard in the URL)
mockHttp.When(HttpMethod.Post, $"https://{Ip.ToString()}/api/jsonrpc")
.Respond("application/json", ResponseStrings.PlcProgramBrowseCodeBlocksSuccess); // Respond with JSON
// Inject the handler or client into your application code
var client = new HttpClient(mockHttp);
client.BaseAddress = new Uri($"https://{Ip.ToString()}");
TestHandler = new ApiHttpClientRequestHandler(client, ApiRequestFactory, ApiResponseChecker);

ApiPlcProgramBrowseCodeBlocksResponse response = await TestHandler.PlcProgramBrowseCodeBlocksAsync();

Assert.That(response.Result.Count == 5);

Assert.That(response.Result[0].Name == "Main");
Assert.That(response.Result[0].BlockType == ApiPlcProgramBlockType.Ob);
Assert.That(response.Result[0].BlockNumber == 1);

Assert.That(response.Result[1].Name == "USEND");
Assert.That(response.Result[1].BlockType == ApiPlcProgramBlockType.Sfb);
Assert.That(response.Result[1].BlockNumber == 8);

Assert.That(response.Result[2].Name == "COPY_HW");
Assert.That(response.Result[2].BlockType == ApiPlcProgramBlockType.Sfc);
Assert.That(response.Result[2].BlockNumber == 65509);

Assert.That(response.Result[3].Name == "PRODTEST");
Assert.That(response.Result[3].BlockType == ApiPlcProgramBlockType.Fb);
Assert.That(response.Result[3].BlockNumber == 65522);

Assert.That(response.Result[4].Name == "FC_14325");
Assert.That(response.Result[4].BlockType == ApiPlcProgramBlockType.Fc);
Assert.That(response.Result[4].BlockNumber == 14325);
}

/// <summary>
///
/// </summary>
/// <returns></returns>
[Test]
public async Task T015_05_ApiPlcProgramBrowseCodeBlocks_EmptyBlockName()
{
var mockHttp = new MockHttpMessageHandler();
// Setup a respond for the user api (including a wildcard in the URL)
mockHttp.When(HttpMethod.Post, $"https://{Ip.ToString()}/api/jsonrpc")
.Respond("application/json", ResponseStrings.PlcProgramBrowseCodeBlocksEmptyBlockName); // Respond with JSON
// Inject the handler or client into your application code
var client = new HttpClient(mockHttp);
client.BaseAddress = new Uri($"https://{Ip.ToString()}");
TestHandler = new ApiHttpClientRequestHandler(client, ApiRequestFactory, ApiResponseChecker);

ApiPlcProgramBrowseCodeBlocksResponse response = await TestHandler.PlcProgramBrowseCodeBlocksAsync();

Assert.That(response.Result.Count == 1);
Assert.That(response.Result[0].Name == String.Empty);
Assert.That(response.Result[0].BlockType == ApiPlcProgramBlockType.Ob);
Assert.That(response.Result[0].BlockNumber == 1);
}

/// <summary>
///
/// </summary>
/// <returns></returns>
[Test]
public void T015_06_ApiPlcProgramBrowseCodeBlocks_StringAsBlockNumber()
{
var mockHttp = new MockHttpMessageHandler();
// Setup a respond for the user api (including a wildcard in the URL)
mockHttp.When(HttpMethod.Post, $"https://{Ip.ToString()}/api/jsonrpc")
.Respond("application/json", ResponseStrings.PlcProgramBrowseCodeBlocksStringAsNumber); // Respond with JSON
// Inject the handler or client into your application code
var client = new HttpClient(mockHttp);
client.BaseAddress = new Uri($"https://{Ip.ToString()}");
TestHandler = new ApiHttpClientRequestHandler(client, ApiRequestFactory, ApiResponseChecker);

Assert.ThrowsAsync<Newtonsoft.Json.JsonSerializationException>(async () => await TestHandler.PlcProgramBrowseCodeBlocksAsync());
}

/// <summary>
///
/// </summary>
/// <returns></returns>
[Test]
public void T015_07_ApiPlcProgramBrowseCodeBlocks_PermissionDenied()
{
var mockHttp = new MockHttpMessageHandler();
// Setup a respond for the user api (including a wildcard in the URL)
mockHttp.When(HttpMethod.Post, $"https://{Ip.ToString()}/api/jsonrpc")
.Respond("application/json", ResponseStrings.PlcProgramBrowseCodeBlocksPermissionDenied); // Respond with JSON
// Inject the handler or client into your application code
var client = new HttpClient(mockHttp);
client.BaseAddress = new Uri($"https://{Ip.ToString()}");
TestHandler = new ApiHttpClientRequestHandler(client, ApiRequestFactory, ApiResponseChecker);

Assert.ThrowsAsync<System.UnauthorizedAccessException>(async () => await TestHandler.PlcProgramBrowseCodeBlocksAsync());
}

/// <summary>
///
/// </summary>
Expand Down
11 changes: 11 additions & 0 deletions tests/Webserver.API.UnitTests/ResponseStrings.cs
Original file line number Diff line number Diff line change
Expand Up @@ -48,10 +48,21 @@ public static class ResponseStrings
public const string PlcProgramBrowseErrorStruct = "{\"jsonrpc\":\"2.0\",\"id\":\"ibf8wom\",\"result\":[{\"name\":\"ERROR_ID\",\"db_number\":1,\"datatype\":\"word\"},{\"name\":\"FLAGS\",\"db_number\":1,\"datatype\":\"byte\"},{\"name\":\"REACTION\",\"db_number\":1,\"datatype\":\"byte\"},{\"name\":\"CODE_ADDRESS\",\"has_children\":true,\"db_number\":1,\"datatype\":\"cref\"},{\"name\":\"MODE\",\"db_number\":1,\"datatype\":\"byte\"},{\"name\":\"OPERAND_NUMBER\",\"db_number\":1,\"datatype\":\"uint\"},{\"name\":\"POINTER_NUMBER_LOCATION\",\"db_number\":1,\"datatype\":\"uint\"},{\"name\":\"SLOT_NUMBER_SCOPE\",\"db_number\":1,\"datatype\":\"uint\"},{\"name\":\"DATA_ADDRESS\",\"has_children\":true,\"db_number\":1,\"datatype\":\"nref\"}]}";
public const string PlcProgramBrowseVarIsNotAStructure = "{\"jsonrpc\":\"2.0\",\"id\":\"5q27h2n\",\"error\":{\"code\":202,\"message\":\"Variable is not a structure\"}}";

public const string PlcProgramBrowseCodeBlocksEmptyResult = "{\"jsonrpc\":\"2.0\",\"id\":\"y9vedkb9\",\"result\":[]}";
public const string PlcProgramBrowseCodeBlocksInvalidParams = "{\"jsonrpc\":\"2.0\",\"id\":55,\"error\":{\"code\":-32602,\"message\":\"Invalid Params\"}}";
public const string PlcProgramBrowseCodeBlocksSuccess = "{\"jsonrpc\":\"2.0\",\"id\":96,\"result\":[{\"name\":\"Main\",\"block_number\":1,\"block_type\":\"ob\"},{\"name\":\"USEND\",\"block_number\":8,\"block_type\":\"sfb\"},{\"name\":\"COPY_HW\",\"block_number\":65509,\"block_type\":\"sfc\"},{\"name\":\"PRODTEST\",\"block_number\":65522,\"block_type\":\"fb\"},{\"name\":\"FC_14325\",\"block_number\":14325,\"block_type\":\"fc\"}]}";
public const string PlcProgramBrowseCodeBlocksEmptyBlockName = "{\"jsonrpc\":\"2.0\",\"id\":96,\"result\":[{\"name\":\"\",\"block_number\":1,\"block_type\":\"ob\"}]}";
public const string PlcProgramBrowseCodeBlocksStringAsNumber = "{\"jsonrpc\":\"2.0\",\"id\":96,\"result\":[{\"name\":\"Main\",\"block_number\":\"abcdefg\",\"block_type\":\"ob\"},{\"name\":\"USEND\",\"block_number\":8,\"block_type\":\"sfb\"},{\"name\":\"COPY_HW\",\"block_number\":65509,\"block_type\":\"sfc\"},{\"name\":\"PRODTEST\",\"block_number\":65522,\"block_type\":\"sfc\"}]}";
public const string PlcProgramBrowseCodeBlocksPermissionDenied = "{\"jsonrpc\":\"2.0\",\"id\":50,\"error\":{\"code\":2,\"message\":\"Permission denied\"}}";

public const string PlcProgramInvalidAddress = "{\"jsonrpc\":\"2.0\",\"id\":\"5uxrl166\",\"error\":{\"code\":201,\"message\":\"Invalid address\"}}";
public const string PlcProgramAddressDoesNotExist = "{\"jsonrpc\":\"2.0\",\"id\":\"8buk8ryn\",\"error\":{\"code\":200,\"message\":\"Address does not exist\"}}";
public const string PlcProgramnInvalidArrayIndex = "{\"jsonrpc\":\"2.0\",\"id\":\"f5eqwla\",\"error\":{\"code\":203,\"message\":\"Invalid array index\"}}";

public const string PlcProgramDownloadProfilingDataSuccess = "{\"jsonrpc\":\"2.0\",\"id\": 6,\"result\":\"jgxikeMgLryvP0YoHc.eqt8BY787\"}";
public const string PlcProgramDownloadProfilingDataPermissionDenied = "{\"jsonrpc\":\"2.0\",\"id\": 18,\"error\":{\"code\": 2,\"message\":\"Permission denied\"}}";
public const string PlcProgramDownloadProfilingDataNoResources = "{\"jsonrpc\":\"2.0\",\"id\":28,\"error\":{\"code\":4,\"message\":\"No Resources\"}}";

public const string PlcProgramUnsupportedAddress = "{\"jsonrpc\":\"2.0\",\"id\":\"1wwe2z8j\",\"error\":{\"code\":204,\"message\":\"Unsupported address\"}}";

public const string PlcProgramReadFalseBool = "{\"jsonrpc\":\"2.0\",\"id\":\"aax109lc\",\"result\":false}";
Expand Down
Loading