Skip to content

Commit

Permalink
add ApiPlcProgramBlockType enum (#44)
Browse files Browse the repository at this point in the history
  • Loading branch information
KircMax authored Dec 4, 2023
1 parent 3d50e43 commit 7e6af02
Show file tree
Hide file tree
Showing 5 changed files with 268 additions and 8 deletions.
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

0 comments on commit 7e6af02

Please sign in to comment.