Repository: microsoft/onefuzz
File: src/ApiService/ApiService/onefuzzlib/NodeOperations.cs (C#)

Code before:

        return false;
    }

    public async Async.Task<Node> SetState(Node node, NodeState state) {
        if (node.State == state) {
            return node;
        }
        _logTracer.Event($"SetState Node {node.MachineId:Tag:MachineId} {node.State:Tag:From} - {state:Tag:To}");

        node = node with { State = state };
        await _context.Events.SendEvent(new EventNodeStateUpdated(
            node.MachineId,
            node.ScalesetId,
            node.PoolName,
            state
        ));

        var r = await Update(node);
        if (!r.IsOk) {
            _logTracer.Error($"Failed to update node for: {node.MachineId:Tag:MachineId} {state:Tag:State} due to {r.ErrorV:Tag:Error}");
            // TODO: this should error out
        }

        return node;
    }

    public static string SearchStatesQuery(
        Guid? poolId = default,
        Guid? scaleSetId = default,
        IEnumerable<NodeState>? states = default,
        PoolName? poolName = default,
        int? numResults = default) {

        List<string> queryParts = new();

        if (poolId is not null) {
            queryParts.Add($"(pool_id eq '{poolId}')");
        }

        if (poolName is not null) {
            queryParts.Add($"(PartitionKey eq '{poolName.String}')");
        }

        if (scaleSetId is not null) {
            queryParts.Add($"(scaleset_id eq '{scaleSetId}')");
        }

        if (states is not null) {
            var q = Query.EqualAnyEnum("state", states);
            queryParts.Add($"({q})");

Review comment (bug):
this was first bug - SearchStatesQuery would ignore current version node. We do not want that. (And Python code does not ignore it ether, so this fix is just aligning implementation with Python code)

Code after:
        return false;
    }

    public async Async.Task<Node> SetState(Node node, NodeState state) {
        if (node.State != state) {
            _logTracer.Event($"SetState Node {node.MachineId:Tag:MachineId} {node.State:Tag:From} - {state:Tag:To}");

            node = node with { State = state };
            await _context.Events.SendEvent(new EventNodeStateUpdated(
                node.MachineId,
                node.ScalesetId,
                node.PoolName,
                state
            ));
        }

        var r = await Update(node);
        if (!r.IsOk) {
            _logTracer.Error($"Failed to update node for: {node.MachineId:Tag:MachineId} {state:Tag:State} due to {r.ErrorV:Tag:Error}");
            // TODO: this should error out
        }

        return node;
    }

    public static string SearchStatesQuery(
        Guid? poolId = default,
        Guid? scaleSetId = default,
        IEnumerable<NodeState>? states = default,
        PoolName? poolName = default,
        int? numResults = default) {

        List<string> queryParts = new();

        if (poolId is not null) {
            queryParts.Add($"(pool_id eq '{poolId}')");
        }

        if (poolName is not null) {
            queryParts.Add($"(PartitionKey eq '{poolName.String}')");
        }

        if (scaleSetId is not null) {
            queryParts.Add($"(scaleset_id eq '{scaleSetId}')");
        }

        if (states is not null) {
            var q = Query.EqualAnyEnum("state", states);
            queryParts.Add($"({q})");
        }