From c842a10f738fe52ea8900456f18f8e063a8b9878 Mon Sep 17 00:00:00 2001 From: yongenaelf <132553186+yongenaelf@users.noreply.github.com> Date: Fri, 18 Oct 2024 15:32:26 +0800 Subject: [PATCH 01/15] Create load-test.yml --- .github/workflows/load-test.yml | 19 +++++++++++++++++++ 1 file changed, 19 insertions(+) create mode 100644 .github/workflows/load-test.yml diff --git a/.github/workflows/load-test.yml b/.github/workflows/load-test.yml new file mode 100644 index 0000000..5636a90 --- /dev/null +++ b/.github/workflows/load-test.yml @@ -0,0 +1,19 @@ +name: Artillery Load Test + +on: + push: + branches: + - load-test + +jobs: + artillery: + runs-on: ubuntu-latest + + steps: + - name: Checkout repository + uses: actions/checkout@v2 + + - name: Execute load tests + uses: artilleryio/action-cli@v1 + with: + command: run tests/performance/main.yml From d0dd3c4d400144b2850bf93c62d7c2aa60f5bf65 Mon Sep 17 00:00:00 2001 From: yongenaelf <132553186+yongenaelf@users.noreply.github.com> Date: Fri, 18 Oct 2024 15:44:59 +0800 Subject: [PATCH 02/15] ci: load test script --- tests/performance/main.yml | 103 +++++++++++++++++++++++++++++++++++++ 1 file changed, 103 insertions(+) create mode 100644 tests/performance/main.yml diff --git a/tests/performance/main.yml b/tests/performance/main.yml new file mode 100644 index 0000000..0943938 --- /dev/null +++ b/tests/performance/main.yml @@ -0,0 +1,103 @@ +config: + target: "https://playground-next.test.aelf.dev" +scenarios: + - flow: + - post: + url: "/api/build" + json: + files: + - path: src/HelloWorld.cs + contents: "using AElf.Sdk.CSharp;\nusing Google.Protobuf.WellKnownTypes;\n\nnamespace + AElf.Contracts.HelloWorld\n{\n // Contract class must inherit the base class + generated from the proto file\n public class HelloWorld : HelloWorldContainer.HelloWorldBase\n + \ {\n // A method that modifies the contract state\n public override + Empty Update(StringValue input)\n {\n // Set the message value + in the contract state\n State.Message.Value = input.Value;\n // + Emit an event to notify listeners about something happened during the execution + of this method\n Context.Fire(new UpdatedMessage\n {\n Value + = input.Value\n });\n return new Empty();\n }\n\n + \ // A method that read the contract state\n public override StringValue + Read(Empty input)\n {\n // Retrieve the value from the state\n + \ var value = State.Message.Value;\n // Wrap the value in + the return type\n return new StringValue\n {\n Value + = value\n };\n }\n }\n \n}" + - path: src/HelloWorld.csproj + contents: "\n \n net6.0\n + \ AElf.Contracts.HelloWorld\n true\n + \ true\n \n + \ \n $(MSBuildProjectDirectory)/$(BaseIntermediateOutputPath)$(Configuration)/$(TargetFramework)/\n + \ \n\n \n + \ \n \n \n \n\n \n \n \n all\n runtime; + build; native; contentfiles; analyzers; buildtransitive\n \n + \ \n\n\n " + - path: src/HelloWorldState.cs + contents: "using AElf.Sdk.CSharp.State;\n\nnamespace AElf.Contracts.HelloWorld\n{\n + \ // The state class is access the blockchain state\n public class HelloWorldState + : ContractState \n {\n // A state that holds string value\n public + StringState Message { get; set; }\n }\n}" + - path: src/Protobuf/contract/hello_world_contract.proto + contents: "syntax = \"proto3\";\n\nimport \"aelf/options.proto\";\nimport \"google/protobuf/empty.proto\";\nimport + \"google/protobuf/wrappers.proto\";\nimport \"Protobuf/reference/acs12.proto\";\n// + The namespace of this class\noption csharp_namespace = \"AElf.Contracts.HelloWorld\";\n\nservice + HelloWorld {\n // The name of the state class the smart contract is going to + use to access blockchain state\n option (aelf.csharp_state) = \"AElf.Contracts.HelloWorld.HelloWorldState\";\n + \ option (aelf.base) = \"Protobuf/reference/acs12.proto\";\n \n // Actions (methods + that modify contract state)\n // Stores the value in contract state\n rpc Update + (google.protobuf.StringValue) returns (google.protobuf.Empty) {\n }\n\n // Views + (methods that don't modify contract state)\n // Get the value stored from contract + state\n rpc Read (google.protobuf.Empty) returns (google.protobuf.StringValue) + {\n option (aelf.is_view) = true;\n }\n}\n\n// An event that will be emitted + from contract method call\nmessage UpdatedMessage {\n option (aelf.is_event) + = true;\n string value = 1;\n}" + - path: src/Protobuf/message/authority_info.proto + contents: |- + syntax = "proto3"; + + import "aelf/core.proto"; + + option csharp_namespace = "AElf.Contracts.HelloWorld"; + + message AuthorityInfo { + aelf.Address contract_address = 1; + aelf.Address owner_address = 2; + } + - path: src/Protobuf/reference/acs12.proto + contents: |- + /** + * AElf Standards ACS12(User Contract Standard) + * + * Used to manage user contract. + */ + syntax = "proto3"; + + package acs12; + + import public "aelf/options.proto"; + import public "google/protobuf/empty.proto"; + import public "google/protobuf/wrappers.proto"; + import "aelf/core.proto"; + + option (aelf.identity) = "acs12"; + option csharp_namespace = "AElf.Standards.ACS12"; + + service UserContract{ + + } + + //Specified method fee for user contract. + message UserContractMethodFees { + // List of fees to be charged. + repeated UserContractMethodFee fees = 2; + // Optional based on the implementation of SetConfiguration method. + bool is_size_fee_free = 3; + } + + message UserContractMethodFee { + // The token symbol of the method fee. + string symbol = 1; + // The amount of fees to be charged. + int64 basic_fee = 2; + } From 8f8cd0721462aca6e9762c7660bc521cf019aae5 Mon Sep 17 00:00:00 2001 From: yongenaelf <132553186+yongenaelf@users.noreply.github.com> Date: Fri, 18 Oct 2024 15:50:00 +0800 Subject: [PATCH 03/15] ci: add load test phases --- tests/performance/main.yml | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/tests/performance/main.yml b/tests/performance/main.yml index 0943938..21a3385 100644 --- a/tests/performance/main.yml +++ b/tests/performance/main.yml @@ -1,5 +1,10 @@ config: target: "https://playground-next.test.aelf.dev" + phases: + - duration: 60 + arrivalRate: 5 # Start with 5 requests per second + - duration: 120 + arrivalRate: 10 # Increase to 10 requests per second scenarios: - flow: - post: From 9c77b8bdc7ea5c58b946dcdf4e40f9b52a865294 Mon Sep 17 00:00:00 2001 From: yongenaelf <132553186+yongenaelf@users.noreply.github.com> Date: Fri, 18 Oct 2024 16:00:34 +0800 Subject: [PATCH 04/15] ci: artillery cloud --- .github/workflows/load-test.yml | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/.github/workflows/load-test.yml b/.github/workflows/load-test.yml index 5636a90..415d717 100644 --- a/.github/workflows/load-test.yml +++ b/.github/workflows/load-test.yml @@ -16,4 +16,6 @@ jobs: - name: Execute load tests uses: artilleryio/action-cli@v1 with: - command: run tests/performance/main.yml + command: run tests/performance/main.yml --record + env: + ARTILLERY_CLOUD_API_KEY: ${{ secrets.ARTILLERY_CLOUD_KEY }} \ No newline at end of file From 81a9921a13cc60d6d0778c1fccbe66a79a592b2a Mon Sep 17 00:00:00 2001 From: yongenaelf <132553186+yongenaelf@users.noreply.github.com> Date: Fri, 18 Oct 2024 16:36:25 +0800 Subject: [PATCH 05/15] Update main.yml try single test --- tests/performance/main.yml | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/tests/performance/main.yml b/tests/performance/main.yml index 21a3385..c9026e2 100644 --- a/tests/performance/main.yml +++ b/tests/performance/main.yml @@ -1,10 +1,10 @@ config: target: "https://playground-next.test.aelf.dev" - phases: - - duration: 60 - arrivalRate: 5 # Start with 5 requests per second - - duration: 120 - arrivalRate: 10 # Increase to 10 requests per second + # phases: + # - duration: 60 + # arrivalRate: 5 # Start with 5 requests per second + # - duration: 120 + # arrivalRate: 10 # Increase to 10 requests per second scenarios: - flow: - post: From f57b9fd637e5e89a629bd328b7dd1805860384c5 Mon Sep 17 00:00:00 2001 From: yongenaelf <132553186+yongenaelf@users.noreply.github.com> Date: Fri, 18 Oct 2024 16:52:46 +0800 Subject: [PATCH 06/15] fix: request body --- tests/performance/helper.js | 8 +++ tests/performance/main.yml | 99 +----------------------------- tests/performance/requestBody.json | 28 +++++++++ 3 files changed, 38 insertions(+), 97 deletions(-) create mode 100644 tests/performance/helper.js create mode 100644 tests/performance/requestBody.json diff --git a/tests/performance/helper.js b/tests/performance/helper.js new file mode 100644 index 0000000..4f8a16b --- /dev/null +++ b/tests/performance/helper.js @@ -0,0 +1,8 @@ +var JSONFile= require('fs').readFileSync("./requestBody.json"); + +exports.setJSONBody = (req, context, events, next) => { + const requestJSON= JSON.parse(JSONFile); + + context.vars.requestBody = requestJSON; + return next(); +}; \ No newline at end of file diff --git a/tests/performance/main.yml b/tests/performance/main.yml index c9026e2..7d9adbe 100644 --- a/tests/performance/main.yml +++ b/tests/performance/main.yml @@ -1,4 +1,5 @@ config: + processor: "./helper.js" target: "https://playground-next.test.aelf.dev" # phases: # - duration: 60 @@ -9,100 +10,4 @@ scenarios: - flow: - post: url: "/api/build" - json: - files: - - path: src/HelloWorld.cs - contents: "using AElf.Sdk.CSharp;\nusing Google.Protobuf.WellKnownTypes;\n\nnamespace - AElf.Contracts.HelloWorld\n{\n // Contract class must inherit the base class - generated from the proto file\n public class HelloWorld : HelloWorldContainer.HelloWorldBase\n - \ {\n // A method that modifies the contract state\n public override - Empty Update(StringValue input)\n {\n // Set the message value - in the contract state\n State.Message.Value = input.Value;\n // - Emit an event to notify listeners about something happened during the execution - of this method\n Context.Fire(new UpdatedMessage\n {\n Value - = input.Value\n });\n return new Empty();\n }\n\n - \ // A method that read the contract state\n public override StringValue - Read(Empty input)\n {\n // Retrieve the value from the state\n - \ var value = State.Message.Value;\n // Wrap the value in - the return type\n return new StringValue\n {\n Value - = value\n };\n }\n }\n \n}" - - path: src/HelloWorld.csproj - contents: "\n \n net6.0\n - \ AElf.Contracts.HelloWorld\n true\n - \ true\n \n - \ \n $(MSBuildProjectDirectory)/$(BaseIntermediateOutputPath)$(Configuration)/$(TargetFramework)/\n - \ \n\n \n - \ \n \n \n \n\n \n \n \n all\n runtime; - build; native; contentfiles; analyzers; buildtransitive\n \n - \ \n\n\n " - - path: src/HelloWorldState.cs - contents: "using AElf.Sdk.CSharp.State;\n\nnamespace AElf.Contracts.HelloWorld\n{\n - \ // The state class is access the blockchain state\n public class HelloWorldState - : ContractState \n {\n // A state that holds string value\n public - StringState Message { get; set; }\n }\n}" - - path: src/Protobuf/contract/hello_world_contract.proto - contents: "syntax = \"proto3\";\n\nimport \"aelf/options.proto\";\nimport \"google/protobuf/empty.proto\";\nimport - \"google/protobuf/wrappers.proto\";\nimport \"Protobuf/reference/acs12.proto\";\n// - The namespace of this class\noption csharp_namespace = \"AElf.Contracts.HelloWorld\";\n\nservice - HelloWorld {\n // The name of the state class the smart contract is going to - use to access blockchain state\n option (aelf.csharp_state) = \"AElf.Contracts.HelloWorld.HelloWorldState\";\n - \ option (aelf.base) = \"Protobuf/reference/acs12.proto\";\n \n // Actions (methods - that modify contract state)\n // Stores the value in contract state\n rpc Update - (google.protobuf.StringValue) returns (google.protobuf.Empty) {\n }\n\n // Views - (methods that don't modify contract state)\n // Get the value stored from contract - state\n rpc Read (google.protobuf.Empty) returns (google.protobuf.StringValue) - {\n option (aelf.is_view) = true;\n }\n}\n\n// An event that will be emitted - from contract method call\nmessage UpdatedMessage {\n option (aelf.is_event) - = true;\n string value = 1;\n}" - - path: src/Protobuf/message/authority_info.proto - contents: |- - syntax = "proto3"; - - import "aelf/core.proto"; - - option csharp_namespace = "AElf.Contracts.HelloWorld"; - - message AuthorityInfo { - aelf.Address contract_address = 1; - aelf.Address owner_address = 2; - } - - path: src/Protobuf/reference/acs12.proto - contents: |- - /** - * AElf Standards ACS12(User Contract Standard) - * - * Used to manage user contract. - */ - syntax = "proto3"; - - package acs12; - - import public "aelf/options.proto"; - import public "google/protobuf/empty.proto"; - import public "google/protobuf/wrappers.proto"; - import "aelf/core.proto"; - - option (aelf.identity) = "acs12"; - option csharp_namespace = "AElf.Standards.ACS12"; - - service UserContract{ - - } - - //Specified method fee for user contract. - message UserContractMethodFees { - // List of fees to be charged. - repeated UserContractMethodFee fees = 2; - // Optional based on the implementation of SetConfiguration method. - bool is_size_fee_free = 3; - } - - message UserContractMethodFee { - // The token symbol of the method fee. - string symbol = 1; - // The amount of fees to be charged. - int64 basic_fee = 2; - } + json: "{{ requestBody }}" \ No newline at end of file diff --git a/tests/performance/requestBody.json b/tests/performance/requestBody.json new file mode 100644 index 0000000..b62b1f0 --- /dev/null +++ b/tests/performance/requestBody.json @@ -0,0 +1,28 @@ +{ + "files": [ + { + "path": "src/HelloWorld.cs", + "contents": "using AElf.Sdk.CSharp;\nusing Google.Protobuf.WellKnownTypes;\n\nnamespace AElf.Contracts.HelloWorld\n{\n // Contract class must inherit the base class generated from the proto file\n public class HelloWorld : HelloWorldContainer.HelloWorldBase\n {\n // A method that modifies the contract state\n public override Empty Update(StringValue input)\n {\n // Set the message value in the contract state\n State.Message.Value = input.Value;\n // Emit an event to notify listeners about something happened during the execution of this method\n Context.Fire(new UpdatedMessage\n {\n Value = input.Value\n });\n return new Empty();\n }\n\n // A method that read the contract state\n public override StringValue Read(Empty input)\n {\n // Retrieve the value from the state\n var value = State.Message.Value;\n // Wrap the value in the return type\n return new StringValue\n {\n Value = value\n };\n }\n }\n \n}" + }, + { + "path": "src/HelloWorld.csproj", + "contents": "\n \n net6.0\n AElf.Contracts.HelloWorld\n true\n true\n \n \n $(MSBuildProjectDirectory)/$(BaseIntermediateOutputPath)$(Configuration)/$(TargetFramework)/\n \n\n \n \n \n \n \n\n \n \n \n all\n runtime; build; native; contentfiles; analyzers; buildtransitive\n \n \n\n\n " + }, + { + "path": "src/HelloWorldState.cs", + "contents": "using AElf.Sdk.CSharp.State;\n\nnamespace AElf.Contracts.HelloWorld\n{\n // The state class is access the blockchain state\n public class HelloWorldState : ContractState \n {\n // A state that holds string value\n public StringState Message { get; set; }\n }\n}" + }, + { + "path": "src/Protobuf/contract/hello_world_contract.proto", + "contents": "syntax = \"proto3\";\n\nimport \"aelf/options.proto\";\nimport \"google/protobuf/empty.proto\";\nimport \"google/protobuf/wrappers.proto\";\nimport \"Protobuf/reference/acs12.proto\";\n// The namespace of this class\noption csharp_namespace = \"AElf.Contracts.HelloWorld\";\n\nservice HelloWorld {\n // The name of the state class the smart contract is going to use to access blockchain state\n option (aelf.csharp_state) = \"AElf.Contracts.HelloWorld.HelloWorldState\";\n option (aelf.base) = \"Protobuf/reference/acs12.proto\";\n \n // Actions (methods that modify contract state)\n // Stores the value in contract state\n rpc Update (google.protobuf.StringValue) returns (google.protobuf.Empty) {\n }\n\n // Views (methods that don't modify contract state)\n // Get the value stored from contract state\n rpc Read (google.protobuf.Empty) returns (google.protobuf.StringValue) {\n option (aelf.is_view) = true;\n }\n}\n\n// An event that will be emitted from contract method call\nmessage UpdatedMessage {\n option (aelf.is_event) = true;\n string value = 1;\n}" + }, + { + "path": "src/Protobuf/message/authority_info.proto", + "contents": "syntax = \"proto3\";\n\nimport \"aelf/core.proto\";\n\noption csharp_namespace = \"AElf.Contracts.HelloWorld\";\n\nmessage AuthorityInfo {\n aelf.Address contract_address = 1;\n aelf.Address owner_address = 2;\n}" + }, + { + "path": "src/Protobuf/reference/acs12.proto", + "contents": "/**\n * AElf Standards ACS12(User Contract Standard)\n *\n * Used to manage user contract.\n */\nsyntax = \"proto3\";\n\npackage acs12;\n\nimport public \"aelf/options.proto\";\nimport public \"google/protobuf/empty.proto\";\nimport public \"google/protobuf/wrappers.proto\";\nimport \"aelf/core.proto\";\n\noption (aelf.identity) = \"acs12\";\noption csharp_namespace = \"AElf.Standards.ACS12\";\n\nservice UserContract{\n\n}\n\n//Specified method fee for user contract.\nmessage UserContractMethodFees {\n // List of fees to be charged.\n repeated UserContractMethodFee fees = 2;\n // Optional based on the implementation of SetConfiguration method.\n bool is_size_fee_free = 3;\n}\n\nmessage UserContractMethodFee {\n // The token symbol of the method fee.\n string symbol = 1;\n // The amount of fees to be charged.\n int64 basic_fee = 2;\n}" + } + ] +} \ No newline at end of file From a37ebeced8dc9deefcd76c21fd707f7cd4b31b1e Mon Sep 17 00:00:00 2001 From: yongenaelf <132553186+yongenaelf@users.noreply.github.com> Date: Fri, 18 Oct 2024 16:57:11 +0800 Subject: [PATCH 07/15] fix: path --- tests/performance/helper.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tests/performance/helper.js b/tests/performance/helper.js index 4f8a16b..52301e2 100644 --- a/tests/performance/helper.js +++ b/tests/performance/helper.js @@ -1,4 +1,4 @@ -var JSONFile= require('fs').readFileSync("./requestBody.json"); +var JSONFile= require('fs').readFileSync("./tests/performance/requestBody.json"); exports.setJSONBody = (req, context, events, next) => { const requestJSON= JSON.parse(JSONFile); From 97766b298949407bc277e7a73df4074176cef93b Mon Sep 17 00:00:00 2001 From: yongenaelf <132553186+yongenaelf@users.noreply.github.com> Date: Fri, 18 Oct 2024 17:02:42 +0800 Subject: [PATCH 08/15] test api --- tests/performance/main.yml | 2 +- tests/performance/requestBody.json | 24 ++++++++++++++++++++++++ 2 files changed, 25 insertions(+), 1 deletion(-) diff --git a/tests/performance/main.yml b/tests/performance/main.yml index 7d9adbe..b8ad1a1 100644 --- a/tests/performance/main.yml +++ b/tests/performance/main.yml @@ -9,5 +9,5 @@ config: scenarios: - flow: - post: - url: "/api/build" + url: "/api/test" json: "{{ requestBody }}" \ No newline at end of file diff --git a/tests/performance/requestBody.json b/tests/performance/requestBody.json index b62b1f0..be3b4b4 100644 --- a/tests/performance/requestBody.json +++ b/tests/performance/requestBody.json @@ -23,6 +23,30 @@ { "path": "src/Protobuf/reference/acs12.proto", "contents": "/**\n * AElf Standards ACS12(User Contract Standard)\n *\n * Used to manage user contract.\n */\nsyntax = \"proto3\";\n\npackage acs12;\n\nimport public \"aelf/options.proto\";\nimport public \"google/protobuf/empty.proto\";\nimport public \"google/protobuf/wrappers.proto\";\nimport \"aelf/core.proto\";\n\noption (aelf.identity) = \"acs12\";\noption csharp_namespace = \"AElf.Standards.ACS12\";\n\nservice UserContract{\n\n}\n\n//Specified method fee for user contract.\nmessage UserContractMethodFees {\n // List of fees to be charged.\n repeated UserContractMethodFee fees = 2;\n // Optional based on the implementation of SetConfiguration method.\n bool is_size_fee_free = 3;\n}\n\nmessage UserContractMethodFee {\n // The token symbol of the method fee.\n string symbol = 1;\n // The amount of fees to be charged.\n int64 basic_fee = 2;\n}" + }, + { + "path": "test/HelloWorld.Tests.csproj", + "contents": "\n \n net6.0\n AElf.Contracts.HelloWorld\n \n\n \n 0436;CS2002\n \n \n $(MSBuildProjectDirectory)/$(BaseIntermediateOutputPath)$(Configuration)/$(TargetFramework)/\n \n\n \n \n \n \n \n \n \n \n \n \n \n \n all\n runtime; build; native; contentfiles; analyzers; buildtransitive\n \n \n\n \n \n nocontract\n \n \n nocontract\n \n \n stub\n \n \n\n \n \n \n\n \n \n \n \n" + }, + { + "path": "test/HelloWorldTests.cs", + "contents": "using System.Threading.Tasks;\nusing Google.Protobuf.WellKnownTypes;\nusing Shouldly;\nusing Xunit;\n\nnamespace AElf.Contracts.HelloWorld\n{\n // This class is unit test class, and it inherit TestBase. Write your unit test code inside it\n public class HelloWorldTests : TestBase\n {\n [Fact]\n public async Task Update_ShouldUpdateMessageAndFireEvent()\n {\n // Arrange\n var inputValue = \"Hello, World!\";\n var input = new StringValue { Value = inputValue };\n\n // Act\n await HelloWorldStub.Update.SendAsync(input);\n\n // Assert\n var updatedMessage = await HelloWorldStub.Read.CallAsync(new Empty());\n updatedMessage.Value.ShouldBe(inputValue);\n }\n }\n \n}" + }, + { + "path": "test/Protobuf/message/authority_info.proto", + "contents": "syntax = \"proto3\";\n\nimport \"aelf/core.proto\";\n\noption csharp_namespace = \"AElf.Contracts.HelloWorld\";\n\nmessage AuthorityInfo {\n aelf.Address contract_address = 1;\n aelf.Address owner_address = 2;\n}" + }, + { + "path": "test/Protobuf/reference/acs12.proto", + "contents": "/**\n * AElf Standards ACS12(User Contract Standard)\n *\n * Used to manage user contract.\n */\nsyntax = \"proto3\";\n\npackage acs12;\n\nimport public \"aelf/options.proto\";\nimport public \"google/protobuf/empty.proto\";\nimport public \"google/protobuf/wrappers.proto\";\nimport \"aelf/core.proto\";\n\noption (aelf.identity) = \"acs12\";\noption csharp_namespace = \"AElf.Standards.ACS12\";\n\nservice UserContract{\n\n}\n\n//Specified method fee for user contract.\nmessage UserContractMethodFees {\n // List of fees to be charged.\n repeated UserContractMethodFee fees = 2;\n // Optional based on the implementation of SetConfiguration method.\n bool is_size_fee_free = 3;\n}\n\nmessage UserContractMethodFee {\n // The token symbol of the method fee.\n string symbol = 1;\n // The amount of fees to be charged.\n int64 basic_fee = 2;\n}" + }, + { + "path": "test/Protobuf/stub/hello_world_contract.proto", + "contents": "syntax = \"proto3\";\n\nimport \"aelf/options.proto\";\nimport \"google/protobuf/empty.proto\";\nimport \"google/protobuf/wrappers.proto\";\nimport \"Protobuf/reference/acs12.proto\";\n// The namespace of this class\noption csharp_namespace = \"AElf.Contracts.HelloWorld\";\n\nservice HelloWorld {\n // The name of the state class the smart contract is going to use to access blockchain state\n option (aelf.csharp_state) = \"AElf.Contracts.HelloWorld.HelloWorldState\";\n option (aelf.base) = \"Protobuf/reference/acs12.proto\";\n\n // Actions (methods that modify contract state)\n // Stores the value in contract state\n rpc Update (google.protobuf.StringValue) returns (google.protobuf.Empty) {\n }\n\n // Views (methods that don't modify contract state)\n // Get the value stored from contract state\n rpc Read (google.protobuf.Empty) returns (google.protobuf.StringValue) {\n option (aelf.is_view) = true;\n }\n}\n\n// An event that will be emitted from contract method call\nmessage UpdatedMessage {\n option (aelf.is_event) = true;\n string value = 1;\n}" + }, + { + "path": "test/_Setup.cs", + "contents": "using AElf.Cryptography.ECDSA;\nusing AElf.Testing.TestBase;\n\nnamespace AElf.Contracts.HelloWorld\n{\n // The Module class load the context required for unit testing\n public class Module : ContractTestModule\n {\n \n }\n \n // The TestBase class inherit ContractTestBase class, it defines Stub classes and gets instances required for unit testing\n public class TestBase : ContractTestBase\n {\n // The Stub class for unit testing\n internal readonly HelloWorldContainer.HelloWorldStub HelloWorldStub;\n // A key pair that can be used to interact with the contract instance\n private ECKeyPair DefaultKeyPair => Accounts[0].KeyPair;\n\n public TestBase()\n {\n HelloWorldStub = GetHelloWorldContractStub(DefaultKeyPair);\n }\n\n private HelloWorldContainer.HelloWorldStub GetHelloWorldContractStub(ECKeyPair senderKeyPair)\n {\n return GetTester(ContractAddress, senderKeyPair);\n }\n }\n \n}" } ] } \ No newline at end of file From 5d980939d56949f87b419ef7ecbad81b5096fcf2 Mon Sep 17 00:00:00 2001 From: "yongen.loong" Date: Fri, 18 Oct 2024 17:38:20 +0800 Subject: [PATCH 09/15] ci: workflow dispatch --- .github/workflows/load-test.yml | 14 ++++++-------- 1 file changed, 6 insertions(+), 8 deletions(-) diff --git a/.github/workflows/load-test.yml b/.github/workflows/load-test.yml index 415d717..d3c3169 100644 --- a/.github/workflows/load-test.yml +++ b/.github/workflows/load-test.yml @@ -1,21 +1,19 @@ name: Artillery Load Test - + on: - push: - branches: - - load-test - + workflow_dispatch: + jobs: artillery: runs-on: ubuntu-latest - + steps: - name: Checkout repository uses: actions/checkout@v2 - + - name: Execute load tests uses: artilleryio/action-cli@v1 with: command: run tests/performance/main.yml --record env: - ARTILLERY_CLOUD_API_KEY: ${{ secrets.ARTILLERY_CLOUD_KEY }} \ No newline at end of file + ARTILLERY_CLOUD_API_KEY: ${{ secrets.ARTILLERY_CLOUD_KEY }} From 49fdeab0ae746e1514e2a5c17cbb8b605a778b35 Mon Sep 17 00:00:00 2001 From: yongenaelf <132553186+yongenaelf@users.noreply.github.com> Date: Sun, 20 Oct 2024 17:43:14 +0800 Subject: [PATCH 10/15] feat: update load test script --- tests/performance/main.yml | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) diff --git a/tests/performance/main.yml b/tests/performance/main.yml index b8ad1a1..9a16d8f 100644 --- a/tests/performance/main.yml +++ b/tests/performance/main.yml @@ -8,6 +8,8 @@ config: # arrivalRate: 10 # Increase to 10 requests per second scenarios: - flow: - - post: - url: "/api/test" - json: "{{ requestBody }}" \ No newline at end of file + - post: + url: "/playground/build" + formData: + file: + fromFile: "./Archive.zip" From 98a0a697a2f8ed6272c85a0bb7df04338da4d156 Mon Sep 17 00:00:00 2001 From: yongenaelf <132553186+yongenaelf@users.noreply.github.com> Date: Sun, 20 Oct 2024 17:44:02 +0800 Subject: [PATCH 11/15] feat: add load test source files --- tests/performance/Archive.zip | Bin 0 -> 8764 bytes 1 file changed, 0 insertions(+), 0 deletions(-) create mode 100644 tests/performance/Archive.zip diff --git a/tests/performance/Archive.zip b/tests/performance/Archive.zip new file mode 100644 index 0000000000000000000000000000000000000000..1906859b4bd7010b93781318d4d1611af687c030 GIT binary patch literal 8764 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 Date: Sun, 20 Oct 2024 17:46:08 +0800 Subject: [PATCH 12/15] fix: test script --- tests/performance/main.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tests/performance/main.yml b/tests/performance/main.yml index 9a16d8f..ff64bbf 100644 --- a/tests/performance/main.yml +++ b/tests/performance/main.yml @@ -11,5 +11,5 @@ scenarios: - post: url: "/playground/build" formData: - file: + contractFiles: fromFile: "./Archive.zip" From 8f1bb1b226b6ad232122bfde3f2ba24d70b730e1 Mon Sep 17 00:00:00 2001 From: yongenaelf <132553186+yongenaelf@users.noreply.github.com> Date: Sun, 20 Oct 2024 17:48:21 +0800 Subject: [PATCH 13/15] fix: increase the timeout --- tests/performance/main.yml | 2 ++ 1 file changed, 2 insertions(+) diff --git a/tests/performance/main.yml b/tests/performance/main.yml index ff64bbf..fa17a24 100644 --- a/tests/performance/main.yml +++ b/tests/performance/main.yml @@ -1,5 +1,7 @@ config: processor: "./helper.js" + http: + timeout: 60000 target: "https://playground-next.test.aelf.dev" # phases: # - duration: 60 From e848dbfb4a0c7fff7d775a9899c9dde7552647b8 Mon Sep 17 00:00:00 2001 From: yongenaelf <132553186+yongenaelf@users.noreply.github.com> Date: Sun, 20 Oct 2024 17:51:05 +0800 Subject: [PATCH 14/15] fix: use test --- tests/performance/main.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tests/performance/main.yml b/tests/performance/main.yml index fa17a24..cc0d0e2 100644 --- a/tests/performance/main.yml +++ b/tests/performance/main.yml @@ -11,7 +11,7 @@ config: scenarios: - flow: - post: - url: "/playground/build" + url: "/playground/test" formData: contractFiles: fromFile: "./Archive.zip" From eaaf32dd5474b35c3d4fb64a9ada6fd3c470eea2 Mon Sep 17 00:00:00 2001 From: yongenaelf <132553186+yongenaelf@users.noreply.github.com> Date: Sun, 20 Oct 2024 17:53:50 +0800 Subject: [PATCH 15/15] feat: simulate short burst --- tests/performance/main.yml | 8 +++----- 1 file changed, 3 insertions(+), 5 deletions(-) diff --git a/tests/performance/main.yml b/tests/performance/main.yml index cc0d0e2..22ef76c 100644 --- a/tests/performance/main.yml +++ b/tests/performance/main.yml @@ -3,11 +3,9 @@ config: http: timeout: 60000 target: "https://playground-next.test.aelf.dev" - # phases: - # - duration: 60 - # arrivalRate: 5 # Start with 5 requests per second - # - duration: 120 - # arrivalRate: 10 # Increase to 10 requests per second + phases: + - duration: 10 + arrivalRate: 5 # Start with 5 requests per second scenarios: - flow: - post: