Skip to content
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

hydra-api.yaml returns an object when getting evals causing deserialization to fail #1430

Open
eureka-cpu opened this issue Dec 9, 2024 · 6 comments
Labels

Comments

@eureka-cpu
Copy link

Describe the bug
A clear and concise description of what the bug is.

Ref #1427 I'm working on creating a tool in Rust and I've used the open api and openapi-generator-cli to create some Rust bindings. This function was generated from the openapi-generator-cli so it's also possible this is the fault of that, but just in case I'm reporting here as well. This particular function is supposed to return an array of evals (just like how the function for getting jobsets returns a json array of jobsets), at least that's what the function signature indicates, however what is actually returned is an object with a field "evals" which contains the array. This causes deserialization to fail.

To Reproduce
Steps to reproduce the behavior:
See #1427

Expected behavior
A clear and concise description of what you expected to happen.

I just expected the api to return an array of evals, just like it does for jobsets, since the api seems to indicate that's what it should return.

Screenshots
If applicable, add screenshots to help explain your problem.

Here's the code:

pub async fn jobset_project_id_jobset_id_evals_get(
    configuration: &configuration::Configuration,
    project_id: &str,
    jobset_id: &str,
) -> Result<Vec<models::Evaluations>, Error<JobsetProjectIdJobsetIdEvalsGetError>> {
    let local_var_configuration = configuration;

    let local_var_client = &local_var_configuration.client;

    let local_var_uri_str = format!(
        "{}/jobset/{}/{}/evals",
        local_var_configuration.base_path,
        crate::apis::urlencode(project_id),
        crate::apis::urlencode(jobset_id)
    );
    let mut local_var_req_builder =
        local_var_client.request(reqwest::Method::GET, local_var_uri_str.as_str());

    if let Some(ref local_var_user_agent) = local_var_configuration.user_agent {
        local_var_req_builder =
            local_var_req_builder.header(reqwest::header::USER_AGENT, local_var_user_agent.clone());
    }

    let local_var_req = local_var_req_builder.build()?;
    let local_var_resp = local_var_client.execute(local_var_req).await?;

    let local_var_status = local_var_resp.status();
    let local_var_content = local_var_resp.text().await?;

    if !local_var_status.is_client_error() && !local_var_status.is_server_error() {
        serde_json::from_str(&local_var_content).map_err(Error::from)
    } else {
        let local_var_entity: Option<JobsetProjectIdJobsetIdEvalsGetError> =
            serde_json::from_str(&local_var_content).ok();
        let local_var_error = ResponseContent {
            status: local_var_status,
            content: local_var_content,
            entity: local_var_entity,
        };
        Err(Error::ResponseError(local_var_error))
    }
}

Output as described above:

[hydra-api/src/apis/default_api.rs:502:9] &local_var_content = "{\"evals\":[{\"flake\":\"gitlab:sweng-infra/nix/f68b9802b2c32369aec7da31fa5088c3ab584d09\",\"timestamp\":1733370436,\"checkouttime\":0,\"builds\":[1200371,1200372,1200373,1200374,1200375,1200376,1200377,1200378,1200379,1200380,1200381,1200382,1200383,1200384,1200385,1200386,1200387,1200388,1200389,1200390,1200391,1200392,1200393,1200394,1200395,1200396,1200397,1200398,1200399,1200400,1200401,1200402,1200403,1200404,1200405,1200406,1200407,1200408,1200409,1200410,1200411],\"jobsetevalinputs\":{},\"evaltime\":356,\"id\":84895,\"hasnewbuilds\":1}],\"first\":\"?page=1\",\"last\":\"?page=1\"}"
Error: Error while attempting to list evaluations for jobset 'v2-34-devel/v2.34.0-20241205033931-0':

Serde(Error("invalid type: map, expected a sequence", line: 1, column: 0))

Hydra Server:

Please fill out this data as well as you can, but don't worry if you can't -- just do your best.

  • OS and version: [e.g. NixOS 22.05.20211203.ee3794c]
  • Version of Hydra
  • Version of Nix Hydra is built against
  • Version of the Nix daemon

Additional context
Add any other context about the problem here.

@eureka-cpu eureka-cpu added the bug label Dec 9, 2024
@eureka-cpu eureka-cpu changed the title hydra-api.yaml get evaluations function returns incorrect type hydra-api.yaml returns an object when getting evals causing deserialization to fail Dec 9, 2024
@eureka-cpu
Copy link
Author

I could implement a fix on my end and just manually create an implementation of Deserialize for Vec<Evaluations>, but it would be nice if the open api just worked out of the box. If there's a change I can help make please let me know, I'm happy to contribute (:

@eureka-cpu
Copy link
Author

After looking into it more, this json doesn't represent a Vec<Evaluations> but rather just Evaluations... I wonder why the generator expected a vector of this type?

@eureka-cpu
Copy link
Author

After changing the function signature's return type to reflect this, the deserialization still fails:

[hydra-api/src/apis/default_api.rs:505:9] &local_var_content = "{\"evals\":[{\"jobsetevalinputs\":{},\"hasnewbuilds\":1,\"id\":84918,\"evaltime\":357,\"timestamp\":1733410694,\"checkouttime\":0,\"flake\":\"gitlab:sweng-infra/nix/970acfef79bb794c222f22c986569fba70258be6\",\"builds\":[1200762,1200763,1200764,1200765,1200766,1200767,1200768,1200769,1200770,1200771,1200772,1200773,1200774,1200775,1200776,1200777,1200778,1200779,1200780,1200781,1200782,1200783,1200784,1200785,1200786,1200787,1200788,1200789,1200790,1200791,1200792,1200793,1200794,1200795,1200796,1200797,1200798,1200799,1200800,1200801,1200802]}],\"first\":\"?page=1\",\"last\":\"?page=1\"}"
Error: Error while attempting to list evaluations for jobset 'v2-34-devel/v2.34.0-20241205145027-0':

Serde(Error("invalid type: integer `1`, expected struct JobsetEval", line: 1, column: 49))

@eureka-cpu
Copy link
Author

After changing the function signature's return type to reflect this, the deserialization still fails:

[hydra-api/src/apis/default_api.rs:505:9] &local_var_content = "{\"evals\":[{\"jobsetevalinputs\":{},\"hasnewbuilds\":1,\"id\":84918,\"evaltime\":357,\"timestamp\":1733410694,\"checkouttime\":0,\"flake\":\"gitlab:sweng-infra/nix/970acfef79bb794c222f22c986569fba70258be6\",\"builds\":[1200762,1200763,1200764,1200765,1200766,1200767,1200768,1200769,1200770,1200771,1200772,1200773,1200774,1200775,1200776,1200777,1200778,1200779,1200780,1200781,1200782,1200783,1200784,1200785,1200786,1200787,1200788,1200789,1200790,1200791,1200792,1200793,1200794,1200795,1200796,1200797,1200798,1200799,1200800,1200801,1200802]}],\"first\":\"?page=1\",\"last\":\"?page=1\"}"
Error: Error while attempting to list evaluations for jobset 'v2-34-devel/v2.34.0-20241205145027-0':

Serde(Error("invalid type: integer `1`, expected struct JobsetEval", line: 1, column: 49))

maybe it's just unhappy with the 0 = false and 1 = true scheme when deserializing boolean values?

@eureka-cpu
Copy link
Author

eureka-cpu commented Dec 9, 2024

OK, after a bit of debugging here I got it to work. There are three issues:

  1. The function signature expects a json array of Evaluations, but the json returned is just an object representing a single Evaluations
  2. The hasnewbuilds field on JobsetEval expects a boolean, but the deserializer by default doesn't consider integers (0 and 1) as deserializable into boolean values
  3. The evals field on Evaluations for some reason was a HashMap<String, JobsetEval>, but the json returned by the request is an array, not a map

I haven't checked the hydra-api.yaml file for these things, but maybe there's a way to update it so that the generated bindings are correct? Otherwise this could just be an issue with the generator I used.

@eureka-cpu
Copy link
Author

eureka-cpu commented Dec 10, 2024

Running into the same issue with getting builds for some eval. Here's the code:

pub async fn eval_eval_id_builds_get(
    configuration: &configuration::Configuration,
    eval_id: i32,
) -> Result<Vec<std::collections::HashMap<String, models::Build>>, Error<EvalEvalIdBuildsGetError>>
{
    let local_var_configuration = configuration;

    let local_var_client = &local_var_configuration.client;

    let local_var_uri_str = format!(
        "{}/eval/{}/builds",
        local_var_configuration.base_path, eval_id
    );
    let mut local_var_req_builder =
        local_var_client.request(reqwest::Method::GET, local_var_uri_str.as_str());

    if let Some(ref local_var_user_agent) = local_var_configuration.user_agent {
        local_var_req_builder =
            local_var_req_builder.header(reqwest::header::USER_AGENT, local_var_user_agent.clone());
    }

    let local_var_req = local_var_req_builder.build()?;
    let local_var_resp = local_var_client.execute(local_var_req).await?;

    let local_var_status = local_var_resp.status();
    let local_var_content = local_var_resp.text().await?;

    if !local_var_status.is_client_error() && !local_var_status.is_server_error() {
        dbg!(&local_var_content);
        serde_json::from_str(&local_var_content).map_err(Error::from)
    } else {
        let local_var_entity: Option<EvalEvalIdBuildsGetError> =
            serde_json::from_str(&local_var_content).ok();
        let local_var_error = ResponseContent {
            status: local_var_status,
            content: local_var_content,
            entity: local_var_entity,
        };
        Err(Error::ResponseError(local_var_error))
    }
}

The return type is sort of crazy here, not sure why it expects a vector of hashmaps. The json output is just an array of builds, as expected.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
Projects
None yet
Development

No branches or pull requests

1 participant