Skip to content

Commit

Permalink
Merge branch 'master' into users/pbirkhol/add-enum-support-to-cluster…
Browse files Browse the repository at this point in the history
…-to-labview
  • Loading branch information
pbirkhol-ni authored Sep 14, 2023
2 parents 400b393 + b08086d commit 9eaadfe
Show file tree
Hide file tree
Showing 53 changed files with 3,371 additions and 47 deletions.
19 changes: 15 additions & 4 deletions .github/workflows/build_release_artifacts.yml
Original file line number Diff line number Diff line change
Expand Up @@ -68,12 +68,23 @@ jobs:
run: |
$directory = "${{runner.workspace}}/grpc-labview/tests/New_ATS/logs"
Get-ChildItem -Path $directory | ForEach-Object {
if ($_.PSIsContainer -eq $false) {
Write-Host "Contents of $($_.Name):"
Get-Content $_.FullName
# Recursively iterate through all files in subfolders
Get-ChildItem -Path $directory -File -Recurse | Group-Object Directory | ForEach-Object {
$subfolderName = $_.Name
Write-Host "Folder: $subfolderName"
$_.Group | ForEach-Object {
$file = $_
Write-Host "Filename: $($file.Name)"
Write-Host "Contents:"
# Print the content of the file
Get-Content $file.FullName
Write-Host ""
}
Write-Host ""
}
- if: startsWith(github.ref, 'refs/tags/v')
Expand Down
Binary file not shown.
4 changes: 2 additions & 2 deletions tests/New_ATS/.gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,6 @@ venv
*.aliases
*.lvproj
*.lvlps
Generated_server
Generated_client
logs
Generated_server
logs
23 changes: 17 additions & 6 deletions tests/New_ATS/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -6,12 +6,13 @@

2. The configuration of the testing suite is saved in the [testlist.json](pylib/testlist.json) file. We can modify it to run specific tests with specific labview version and bitness according to our needs.

3. For each test, inside the test folder, we have a protofile, a `Python_client` folder that contains the python clients and an `Impl` folder that stores pre-implemented `Start Sync.vi` and `Run Service.vi` for that particular protofile.
3. For each test, inside the test folder, we have a protofile, a `Python_client` folder that contains the python clients, optionally a `Python_server` folder that contains the python server, an `Impl` folder that stores pre-implemented `Start Sync.vi` and `Run Service.vi` for that particular protofile and a `testcases` folder that contain the testcases for each rpc in json format.

4. When executing the testing suite, the following steps are performed for each test:
- Delete the pre-existing `Generated Server` folder that contains the gRPC Server.
- Regenerate the gRPC server using the protofile.
- Copy the `Start Sync.vi` and `Run Service.vi` from the `Impl` folder into the new `Generated Server` folder.
- Regenerate the server (without deleting the previously generated server) if we are not doing clean generation.
- Run the pre-written python clients in the `Python_client` folder which uses pytest to run all the testcases for each rpc. The testcases are defined in the form of json files in the `testcases` folder.
- Prints the verbose output of each testcase onto the terminal.

Expand Down Expand Up @@ -49,15 +50,23 @@ Now follow the below steps to run the testing suite on windows. Currently only w
(By default it runs Labview 2019)

```json
"labview-version": "2019",
"labview_version": "2019",
```

- Modify the value associated with `"labview-bitness"` to run the specified labview version with the sepcified bitness.

(By default it runs Labview 2019 32 bit)

```json
"labview-bitness": "32"
"labview_bitness": "32",
```

- Modify the value associated with `"clean_gen"` to specify whether or not you want to do a clean generation.

(By default it is set to 'true' which means we are doing a clean generation)

```json
"clean_gen": true
```

2. Run the [pylib/run_tests.py](pylib/run_tests.py)
Expand Down Expand Up @@ -90,6 +99,8 @@ Follow the below steps to add more tests in the testing suite.

10. Create a `Python_client` folder and add python clients for each rpc into it that will interact with the LabVIEW gRPC Server. The name of the client can be anything but should strictly end with `_client.py` like `<client_name>_client.py`.

11. Optionally, you may also create a `Python_server` folder and write the python server with all the rpc's defined into it. The name of the python server can be anything but we prefer it to be like `<test_name>_server.py`.

### TODO:

1. Add the following tests:
Expand All @@ -98,9 +109,9 @@ Follow the below steps to add more tests in the testing suite.
- [ ] Reflection tests
- [ ] Client tests (currently we are only testing gRPC Server)
- [ ] Modification scenarios (do some modification after first generation and then generate and test again)
- Add/Remove/modify RPC
- Add/Remove/modify services
- Add/Remove/modify messages
- Add/Remove/modify RPC
- Add/Remove/modify services
- Add/Remove/modify messages
- [ ] Backward compatibility tests (server generated without the current feature but needs to work with the changes to the current features)
- [ ] Imported proto-file tests
- [x] Multiple RPC methods tests
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,12 @@
import pytest
import os

# 'GetFeature' rpc performs the following operations on the 'req' message fields:
# 1) Increments req_latitude by 1 and saves in res_latitude of 'res' message.
# 2) Increments all the integer and decimal fields of req_oneof by 1 and saves in corresponding res_oneof fields of 'res' message.
# 3) Appends '_response' to the string fields of req_oneof and saves in corresponding res_oneof fields of 'res' message.
# 4) Does a NOT operation on the boolean fields of req_oneof and saves in corresponding res_oneof fields of 'res' message.
# 5) Doesn't do any operation on the bytes fields of req_oneof and saves in corresponding res_oneof fields of 'res' message.
def get_GetFeature_output(test_input):

req_latitude = test_input.get('req_latitude')
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,13 @@
import all_datatypes_oneof_pb2_grpc

class GreeterService(all_datatypes_oneof_pb2_grpc.GreeterServiceServicer):

# 'GetFeature' rpc performs the following operations on the 'req' message fields:
# 1) Increments req_latitude by 1 and saves in res_latitude of 'res' message.
# 2) Increments all the integer and decimal fields of req_oneof by 1 and saves in corresponding res_oneof fields of 'res' message.
# 3) Appends '_response' to the string fields of req_oneof and saves in corresponding res_oneof fields of 'res' message.
# 4) Does a NOT operation on the boolean fields of req_oneof and saves in corresponding res_oneof fields of 'res' message.
# 5) Doesn't do any operation on the bytes fields of req_oneof and saves in corresponding res_oneof fields of 'res' message.
def GetFeature(self, request, context):
response = all_datatypes_oneof_pb2.res(res_latitude=request.req_latitude+1)
if request.HasField('req_int32'):
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,12 @@ syntax = "proto3";
package Greeter;

service GreeterService {
// 'GetFeature' rpc performs the following operations on the 'req' message fields:
// 1) Increments req_latitude by 1 and saves in res_latitude of 'res' message.
// 2) Increments all the integer and decimal fields of req_oneof by 1 and saves in corresponding res_oneof fields of 'res' message.
// 3) Appends '_response' to the string fields of req_oneof and saves in corresponding res_oneof fields of 'res' message.
// 4) Does a NOT operation on the boolean fields of req_oneof and saves in corresponding res_oneof fields of 'res' message.
// 5) Doesn't do any operation on the bytes fields of req_oneof and saves in corresponding res_oneof fields of 'res' message.
rpc GetFeature(req) returns (res) {}
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,10 @@
import pytest
import os

# 'GetFeature' rpc performs the following operations on the 'req' message fields:
# 1) Increments req_latitude by 1 and saves in res_latitude.
# 2) Appends '_response' to the req_name field of req_oneof and saves in res_name field of res_oneof.
# 3) Returns the same value of req_color field of req_oneof and saves in res_color field of res_oneof.
def get_GetFeature_output(test_input):
req_latitude = int(test_input.get('req_latitude'))
req_name = test_input['req_oneof'].get('req_name')
Expand All @@ -16,9 +20,11 @@ def get_GetFeature_output(test_input):
response_dict = {}
response_dict['res_latitude'] = response.res_latitude
response_dict['res_oneof'] = {}
response_dict['res_oneof']['res_color'] = enum_oneof_pb2.Color.Name(response.res_color) if response.HasField('res_color') else None
response_dict['res_oneof']['res_name'] = response.res_name if response.HasField('res_name') else None

if response.HasField('res_color'):
response_dict['res_oneof']['res_color'] = enum_oneof_pb2.Color.Name(response.res_color)
if response.HasField('res_name'):
response_dict['res_oneof']['res_name'] = response.res_name

return(response_dict)

def read_json(filepath):
Expand Down
5 changes: 5 additions & 0 deletions tests/New_ATS/Tests/enum-oneof/enum-oneof.proto
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,11 @@ syntax = "proto3";
package Greeter;

service GreeterService {

// 'GetFeature' rpc performs the following operations on the 'req' message fields:
// 1) Increments req_latitude by 1 and saves in res_latitude.
// 2) Appends '_response' to the req_name field of req_oneof and saves in res_name field of res_oneof.
// 3) Returns the same value of req_color field of req_oneof and saves in res_color field of res_oneof.
rpc GetFeature(req) returns (res) {}
}

Expand Down
8 changes: 2 additions & 6 deletions tests/New_ATS/Tests/enum-oneof/testcases/GetFeature.json
Original file line number Diff line number Diff line change
Expand Up @@ -3,30 +3,26 @@
"input": {
"req_latitude": 100,
"req_oneof": {
"req_name": "Enum",
"req_color": null
"req_name": "Enum"
}
},
"output": {
"res_latitude": 101,
"res_oneof": {
"res_name": "Enum_response",
"res_color": null
"res_name": "Enum_response"
}
}
},
{
"input": {
"req_latitude": 100,
"req_oneof": {
"req_name": null,
"req_color": "GREEN"
}
},
"output": {
"res_latitude": 101,
"res_oneof": {
"res_name": null,
"res_color": "GREEN"
}
}
Expand Down
Binary file not shown.
Binary file not shown.
Original file line number Diff line number Diff line change
@@ -0,0 +1,80 @@
import grpc
import enum_streaming_pb2
import enum_streaming_pb2_grpc
import json
import pytest
import os
from enum import Enum

# 'BidirectionalStreamingMethod' rpc performs the following operations on a stream of 'request' message fields and outputs a stream of corresonding 'response' messages:
# 1) Increments request_number by 1 and saves in response_number of 'response' message.
# 2) Appends '_response' to the request_message field and saves in response_message field of 'response' message.
# 3) Save the same request_color enum value in response_color
class Color(Enum):
RED = 0
GREEN = 1
BLUE = 2

def get_BidirectionalStreamingMethod_output(test_input):

responses = []

with grpc.insecure_channel('localhost:50051') as channel:
stub = enum_streaming_pb2_grpc.RouteGuideStub(channel)
def get_requests():
for request in test_input:
request_number = request["request_number"]
request_message = request["request_message"]
request_color = request["request_color"]
if Color.RED.value == request_color:
request_color = Color.RED
if Color.GREEN.value == request_color:
request_color = Color.GREEN
if Color.BLUE.value == request_color:
request_color = Color.BLUE
yield enum_streaming_pb2.request(request_number=request_number, request_message=request_message, request_color=request_color)
response_stream = stub.BidirectionalStreamingMethod(get_requests())
for response in response_stream:
response_dict = {
"response_number": response.response_number,
"response_message": response.response_message,
"response_color": response.response_color,
}
if response_dict["response_color"] == 0:
response_dict["response_color"] = "RED"
if response_dict["response_color"] == 1:
response_dict["response_color"] = "GREEN"
if response_dict["response_color"] == 2:
response_dict["response_color"] = "BLUE"

responses.append(response_dict)

return responses

def read_json(filepath):
with open(filepath, 'r') as file:
test_data = json.load(file)
return test_data

BidirectionalStreamingMethod_json_file_path = f'{os.path.dirname(os.path.dirname(os.path.abspath(__file__)))}/testcases/BidirectionalStreamingMethod.json'

@pytest.mark.parametrize('testcase', read_json(BidirectionalStreamingMethod_json_file_path))
def test_BidirectionalStreamingMethod(testcase):
test_input = testcase['input']
expected = testcase['output']
assert get_BidirectionalStreamingMethod_output(test_input) == expected

if __name__ == "__main__":
res = get_BidirectionalStreamingMethod_output([
{
"request_number": 25,
"request_message": "Hello, World!",
"request_color": "RED"
},
{
"request_number": 52,
"request_message": "Goodbye, World!",
"request_color": "BLUE"
}
])
print(res)
Original file line number Diff line number Diff line change
@@ -0,0 +1,77 @@
import grpc
import enum_streaming_pb2
import enum_streaming_pb2_grpc
import json
import pytest
import os
from enum import Enum

# 'ClientStreamingMethod' rpc performs the following operations on a stream of 'request' message fields and outputs a single 'response' message:
# 1) Adds the values of request_number of each 'request' message and saves the sum in the response_number of the 'response' message.
# 2) Appends the values of all request_message fields and saves the result in response_message of 'response' message.
# 3) Save the same request_color enum value of the last 'request' message in response_color of each 'response' message
class Color(Enum):
RED = 0
GREEN = 1
BLUE = 2

def get_ClientStreamingMethod_output(test_input):

response_dict = {}
with grpc.insecure_channel('localhost:50051') as channel:
stub = enum_streaming_pb2_grpc.RouteGuideStub(channel)
def get_requests():
for request in test_input:
request_number = request["request_number"]
request_message = request["request_message"]
request_color = request["request_color"]
if Color.RED.value == request_color:
request_color = Color.RED
if Color.GREEN.value == request_color:
request_color = Color.GREEN
if Color.BLUE.value == request_color:
request_color = Color.BLUE
yield enum_streaming_pb2.request(request_number=request_number, request_message=request_message, request_color=request_color)
response = stub.ClientStreamingMethod(get_requests())

response_dict = {
"response_number": response.response_number,
"response_message": response.response_message,
"response_color": response.response_color,
}
if response_dict["response_color"] == 0:
response_dict["response_color"] = "RED"
if response_dict["response_color"] == 1:
response_dict["response_color"] = "GREEN"
if response_dict["response_color"] == 2:
response_dict["response_color"] = "BLUE"

return response_dict

def read_json(filepath):
with open(filepath, 'r') as file:
test_data = json.load(file)
return test_data

ClientStreamingMethod_json_file_path = f'{os.path.dirname(os.path.dirname(os.path.abspath(__file__)))}/testcases/ClientStreamingMethod.json'

@pytest.mark.parametrize('testcase', read_json(ClientStreamingMethod_json_file_path))
def test_ClientStreamingMethod(testcase):
test_input = testcase['input']
expected = testcase['output']
assert get_ClientStreamingMethod_output(test_input) == expected

if __name__ == "__main__":
res = get_ClientStreamingMethod_output([
{
"request_number": 25,
"request_message": "Hello, World!",
"request_color": "RED"
},
{
"request_number": 52,
"request_message": "Goodbye, World!",
"request_color": "BLUE"
}
])
print(res)
Loading

0 comments on commit 9eaadfe

Please sign in to comment.