aica-technology / api

AICA API resources
0 stars 0 forks source link

feat(schemas): sequences #128

Closed eeberhard closed 7 months ago

eeberhard commented 7 months ago

Description

This PR addresses the issue by defining a sequencing syntax in the application schema.

To validate mutually exclusive fields in wait and assert, I used a trick with oneOf. Because oneOf must always validate one and only one subschema, putting {} as the first item under oneOf always validates first and effectively prohibits all subsequent schemas.

Review guidelines

Estimated Time of Review: 20 minutes

Checklist before merging:

eeberhard commented 7 months ago

I used the following test cases to check validation behavior, which I think are mostly exhaustive. All items passed / failed as expected.

sequences:
  valid_sequence:
    - load:
        component: foo
    - wait:
        seconds: 10
    - wait:
        component: foo
        predicate: foo
    - wait:
        condition: foo
    - wait:
        component: foo
        predicate: foo
        timeout:
          seconds: 10
          events:
            load:
              component: foo
            unload:
              component: foo
    - wait:
        condition: foo
        timeout:
          seconds: 10
          events:
            load:
              component: foo
            unload:
              component: foo
    - assert:
        component: foo
        predicate: foo
    - assert:
        condition: foo
    - assert:
        component: foo
        predicate: foo
        else:
          load:
            component: foo
          unload:
            component: foo
    - assert:
        condition: foo
        else:
          load:
            component: foo
          unload:
            component: foo
  invalid_sequence:
    - wait:
        seconds: 10
        timeout: { }
    - wait:
        seconds: 10
        timeout:
          seconds: 10
          events: { }
    - wait:
        component: foo
    - wait:
        predicate: foo
    - wait:
        condition: foo
        predicate: foo
    - wait:
        condition: foo
        component: foo
    - wait:
        component: foo
        predicate: foo
        seconds: 10
    - wait:
        condition: foo
        seconds: 10
    - wait:
        condition: foo
        timeout: { }
    - wait:
        condition: foo
        timeout:
          seconds: 10
    - wait:
        condition: foo
        timeout:
          events: { }
    - assert:
        component: foo
    - assert:
        predicate: foo
    - assert:
        condition: foo
        component: foo
    - assert:
        condition: foo
        predicate: foo
    - assert:
        else: {}
eeberhard commented 7 months ago

the oneOf: {} trick is slightly less readable but probably the right way to go

Unfortunately I couldn't seem to make it work any other way. I tried dependencies / dependentProperties, if / else and other not: required formulations but there always seemed to be some missed cases that should have been invalid but passed. I also tried defining each wait / assert object variant separately to see if that would improve the error or help text, but still in that case it gives an unhelpful warning. At least that way is a bit more readable.