-
Notifications
You must be signed in to change notification settings - Fork 909
Adding L0 tests for Legacy NodeHandler logic | Adding 2 Knobs for feature flag & EOL toggle status value #5421
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
base: master
Are you sure you want to change the base?
Conversation
…ed node | L0 tests for node handlers
…quence | Preventing leakage of test specific environment settings for knobs between node handler tests (both new and legacy)
…checks from handlers | Adding string tempalates for errors and warning and removing hard-coded erros and warning from code
…implyfying unit test scenarios to avoid using redundant code | Update NodeHandlerTestBase to reflect the simplified test scenario usage for unning tests
… check inside getnodeLocation function) | Added custom node path L0 tests | Updated test base code to integrate custom node tests
|
/azp run |
|
Azure Pipelines successfully started running 1 pipeline(s). |
sanjuyadav24
left a comment
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Please share a table with all cases mentioned in test cases to validate if any case is not missed and expected behavior in each scenario
| ), | ||
|
|
||
| new TestScenario( | ||
| name: "Node6_DefaultBehavior_EOLPolicyDisabled", |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
whats the difference between above and this test case?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Essentially these are similar scenarios, for default behavior for node 6 when EOL knob is set to false or the knob itself not being available (this however won't happen as we have default value present in agent knobs). Test added just to cover all basis.
|
|
||
| new TestScenario( | ||
| name: "Node6_WithGlobalUseNode10Knob", | ||
| description: "Node6 handler with global Node10 knob: legacy uses Node10, unified ignores deprecated knob and uses Node6", |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
why node10 doesn't overwrite node6 knob?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
AGENT_USE_NODE10 overrides to node 10 in older implementation. In new implementation, as discussed in design discussion(s), we are getting away from using this knob in new approach.
…com/microsoft/azure-pipelines-agent into users/rishabhmalikMS/EOLnodeL0Tests
|
Wrong PR label, use internal instead of enhancement. |
Updated |
…ndler tests - Replace useUnifiedStrategy → useStrategy parameter - Replace unifiedExpectedNode → strategyExpectedNode property - Replace unifiedExpectSuccess → strategyExpectSuccess property - Replace unifiedExpectedError → strategyExpectedError property - Replace shouldMatchBetweenModes → shouldMatchBetweenLegacyAndStrategy property - Update environment variable AGENT_USE_UNIFIED_NODE_STRATEGY → AGENT_USE_NODE_STRATEGY - Update test descriptions to use "strategy-based" instead of "unified" - Update TestScenario class properties and constructor parameters This improves code clarity by using terminology that directly relates to the strategy pattern implementation rather than the generic term "unified".
|
/azp run |
|
Azure Pipelines successfully started running 1 pipeline(s). |
src/Test/L0/NodeHandlerTestBase.cs
Outdated
| if (expectations.ExpectSuccess) | ||
| { | ||
| string actualLocation = nodeHandler.GetNodeLocation( | ||
| node20ResultsInGlibCError: scenario.Node20GlibcError, | ||
| node24ResultsInGlibCError: scenario.Node24GlibcError, | ||
| inContainer: scenario.InContainer); | ||
|
|
||
| string expectedLocation = GetExpectedNodeLocation(expectations.ExpectedNode, scenario, thc); | ||
| Assert.Equal(expectedLocation, actualLocation); | ||
| } |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
What does ExpectSuccess mean? We can assert the output of GetNodeLocation with our ExpectedNodeLocation, to handle failure of the function GetNodeLocation we can maybe use a try catch.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This is removed as per our discussion on below comment
src/Test/L0/NodeHandlerTestBase.cs
Outdated
| var exception = Assert.Throws(scenario.ExpectedErrorType ?? typeof(FileNotFoundException), | ||
| () => nodeHandler.GetNodeLocation( | ||
| node20ResultsInGlibCError: scenario.Node20GlibcError, | ||
| node24ResultsInGlibCError: scenario.Node24GlibcError, | ||
| inContainer: scenario.InContainer)); | ||
|
|
||
| if (!string.IsNullOrEmpty(expectations.ExpectedError)) | ||
| { | ||
| Assert.Contains(expectations.ExpectedError, exception.Message); | ||
| } |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
If we are expecting an Exception to be thrown by function, why don't we catch the exception and there we check if the exception was expected, in this way we will not have to call the function GetNodeLocation twice.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This is updated to use try-catch approach and reduce fields from test scenario simplifying them further
src/Agent.Sdk/Knob/AgentKnobs.cs
Outdated
|
|
||
| public static readonly Knob EnableEOLNodeVersionPolicy = new Knob( | ||
| nameof(EnableEOLNodeVersionPolicy), | ||
| "When enabled, automatically upgrades tasks using end-of-life Node.js versions (6, 10, 16) to supported versions (Node 20.1 or Node 24). Throws error if no supported versions are available on the agent.", |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This is slightly confusing, we are not upgrading tasks, rather when flag is enabled we disregard the EOL Node versions a task have.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This is updated to be more descriptive
| name: "Node6_EOLPolicyEnabled_UpgradesToNode24", | ||
| description: "Node6 handler with EOL policy: legacy allows Node6, strategy-based upgrades to Node24", | ||
| handlerData: typeof(NodeHandlerData), | ||
| knobs: new() { ["AGENT_ENABLE_EOL_NODE_VERSION_POLICY"] = "true" }, |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I think after Sayantan suggestion, we have changed to AGENT_RESTRICT_EOL_NODE_VERSIONS in Agent Knob, but forget to change here and multiple places, could you please check if we want to update here as well.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This is updated
| legacyExpectedNode: "node10", | ||
| legacyExpectSuccess: true, | ||
| strategyExpectedNode: "node", | ||
| strategyExpectSuccess: true, |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
why this should use node6?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Because in new implementation node 10 (useNode10) knob is deprecated.
| inContainer: scenario.InContainer); | ||
|
|
||
| string expectedLocation = GetExpectedNodeLocation(expectations.ExpectedNode, scenario, thc); | ||
| Assert.Equal(expectedLocation, actualLocation); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
in the scenario we had two values, legacyexpected value and strategy expected value, here we are checking only one
is this expected?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Yes, right now this is expected. Because the tests are running only on existing original code of getNodeLocation. With our strategy code integration both node expectation will be included here.
…fields | Using Trt - Catch intest rnner code instead of this to reduce complexity | updated agnet knob text || Updated knob description to be more meaningful
|
/azp run |
|
Azure Pipelines successfully started running 1 pipeline(s). |
Context
This PR introduces comprehensive L0 test specifications for NodeHandler behavior to establish a test-driven development foundation for upcoming EOL (End of Life) Node.js version policy and unified node selection strategy improvements. The test specifications define expected behaviors for both current legacy implementation and future unified strategy implementation.
Also added 2 knobs, one for feature flag usage to switch between legacy and new Node selection process. Another, to read the EOL toggle status value injected by server when user changes task settings from org settings from ADO.
Related Work: This is the first PR in a multi-part effort to modernize Node.js version handling in Azure Pipelines Agent with proper EOL policy enforcement and custom node path support.
Workitems links
Description
Added comprehensive test infrastructure and specifications for NodeHandler with detailed test scenarios covering:
Test Infrastructure:
NodeHandlerTestBase.cs- Clean base class for NodeHandler test execution with environment setup/teardownNodeHandlerL0.TestSpecifications.cs- Comprehensive test scenarios covering all Node.js versions and edge casesNodeHandlerL0.AllSpecs.cs- Unified test runner executing all scenariosNodeHandlerCollections.cs- Test collection configuration for proper isolationTest Coverage Areas:
2. Node6 Scenarios - Legacy Node 6.x behavior and EOL policy interactions
3. Node10 Scenarios - Node 10.x behavior and EOL policy interactions
4. Node16 Scenarios - Node 16.x behavior and EOL policy interactions
5. Node20 Scenarios - Current default Node 20.x behavior
6. Node24 Scenarios - Latest Node 24.x support
7. Container Scenarios - Node selection in containerized environments
8. EOL Policy Scenarios - End-of-life version handling differences between legacy and unified strategies
Test Structure: Each test scenario includes:
Details of each test scenario added/covered: Test scenarios
Risk Assessment (Low / Medium / High)
Low Risk - This PR contains only test code with no changes to production logic. The tests currently run against existing legacy NodeHandler implementation, with some CustomNode tests intentionally failing to demonstrate implementation gaps for future development.
Unit Tests Added or Updated (Yes / No)
Yes
Additional Testing Performed
List manual or automated tests performed beyond unit tests (e.g., integration, scenario, regression).
Change Behind Feature Flag (Yes / No)
Not applicable - This PR contains only test code with no production changes requiring feature flags.
Tech Design / Approach
Documentation Changes Required (Yes/No)
Test-First Development Approach:
Logging Added/Updated (Yes/No)
Telemetry Added/Updated (Yes/No)
Rollback Scenario and Process (Yes/No)
Dependency Impact Assessed and Regression Tested (Yes/No)