javrasya / django-river

Django workflow library that supports on the fly changes ⛵
BSD 3-Clause "New" or "Revised" License
742 stars 105 forks source link

There is no available initial state for the content type while testing #74

Closed superandrew closed 5 years ago

superandrew commented 5 years ago

When I create an integration test, I create objects in the DB for which I have defined a state field.

        p = Procedure.objects.create()

In django admin I defined 4 states, and 3 transitions

Screenshot 2019-05-12 at 17 46 39

So I understood from the documentation that since CREATED is never a destination state, django-river would have guessed that this was the initial state.

But I get this error:

raise RiverException(ErrorCode.NO_AVAILABLE_INITIAL_STATE, 'There is no available initial state for the content type %s. ' % self._content_type)
river.utils.exceptions.RiverException: There is no available initial state for the content type procedure. 

I'm completely lost, as I understand that this is common but I haven't find a solution, also looking at similar issues.

Any idea?

Thanks

superandrew commented 5 years ago

I notice that in my River applications I have just

States and Transition Approval Meta entities to add or modify. No Transitions or Proceeding Meta like in the tutorial. Does that mean that I miss something from the setup?

superandrew commented 5 years ago

this is what I tried, after understanding that many of the tutorials refer to old version of the framework:

        cr = State.objects.create(label="Created", slug='cr')
        sb = State.objects.create(label="Submitted", slug='sb')
        va = State.objects.create(label="Validated", slug='va')
        rf = State.objects.create(label="Refused", slug='rf')
        cr.save()
        sb.save()
        va.save()
        rf.save()

        content_type = ContentType.objects.get_for_model(Procedure)

        transition_am1 = TransitionApprovalMeta.objects.create(source_state=cr, destination_state=sb, content_type=content_type)
        transition_am2 = TransitionApprovalMeta.objects.create(source_state=sb, destination_state=va, content_type=content_type)
        transition_am3 = TransitionApprovalMeta.objects.create(source_state=sb, destination_state=rf, content_type=content_type)
        transition_am1.save()
        transition_am2.save()
        transition_am3.save()

In a non testing scenario I suppose that you should run migrate, or maybe there is something that I am still missing.

My test suite starts with:

140549272366536 field doesn't seem have any transition approval meta in database. You should create it's TransitionApprovalMeta

then, for every test in which I try to create programmatically a Procedure,

line 38, in initial_state raise RiverException(ErrorCode.NO_AVAILABLE_INITIAL_STATE, 'There is no available initial state for the content type %s. ' % self._content_type) river.utils.exceptions.RiverException: There is no available initial state for the content type procedure.

superandrew commented 5 years ago

ok, I was able to fix it. The problem was that (as a fool) I was doing the setup in the setup method, so every case didn't have data. So Now it works, passing the first state to the object I create

def create_workflow():
cr = State.objects.create(label="Created", slug='cr')
sb = State.objects.create(label="Submitted", slug='sb')
va = State.objects.create(label="Validated", slug='va')
rf = State.objects.create(label="Refused", slug='rf')
cr.save()
sb.save()
va.save()
rf.save()

content_type = ContentType.objects.get_for_model(Procedure)

transition_am1 = TransitionApprovalMeta.objects.create(source_state=cr, destination_state=sb,
                                                       content_type=content_type)
transition_am2 = TransitionApprovalMeta.objects.create(source_state=sb, destination_state=va,
                                                       content_type=content_type)
transition_am3 = TransitionApprovalMeta.objects.create(source_state=sb, destination_state=rf,
                                                       content_type=content_type)
transition_am1.save()
transition_am2.save()
transition_am3.save()

return cr

then,

  p = Procedure.objects.create(current_state=create_workflow())

however, I still have this: 140283630478712 field doesn't seem have any transition approval meta in database. You should create it's TransitionApprovalMeta when starting tests.

superandrew commented 5 years ago

When in functional test I post an object, even after the create_workflow call, I have the same error. probably I should put an initial state in the perform_create override when I am in test mode but I think this kind of misses the point of the initial state guessing.

ErrorCode.NO_AVAILABLE_INITIAL_STATE

In normal mode I have no errors, apart from the continuous <number>field doesn't seem have any transition approval meta in database. You should create it's TransitionApprovalMeta when starting tests. warning.

javrasya commented 5 years ago

Hi @superandrew, it seems like you are not setting field_name of TransitionApprovalMeta in your create workflow function. Since you can have multiple workflows for the same model regarding the different model fields, this is the only way that django-river would figure out what workflow it is. It is weird that django allows you to create a TransitionApprovalMeta without a field name. I would not expect that.

But apart from that, I can say that the warnings and error messages should definitely be improved with the field_name part as well.

superandrew commented 5 years ago

oh, wow. Silly me. It works now.

What do you think about the

140332700806376 field doesn't seem have any transition approval meta in database. You should create it's TransitionApprovalMeta warning I see everytime I launch django and/or the test suite? Is this a misconfiguration, or is it normal? Also, is it normal that everytime I launch makemigrations I've got a new migration with that id changed?

Thanks!

javrasya commented 5 years ago

There seems to be something wrong with field_name error message though. 140549272366536 in the message is actually the field name. But I don't know why it thinks that this number is the field name :-)

I will take a look at this when I have time. But you try setting your field_name in the TransitionApprovalMeta. It should fix it.

Here is an example of creating it programmatically. It is with factory_boy library but the idea is the same.

https://github.com/javrasya/django-river/blob/master/river/tests/base_test.py

superandrew commented 5 years ago

thanks! however setting the field fixed the error, so all tests now run

superandrew commented 5 years ago

@javrasya I think there still is a problem with the fields because every time I run django I have this message:

140692356329112 field doesn't seem have any transition approval meta in database. You should create it's TransitionApprovalMeta

and everytime I run manage.py makemigrations django river creates a new migration slightly changing the field name:


from django.db import migrations
import django.db.models.deletion
import river.models.fields.state

class Migration(migrations.Migration):

    dependencies = [
        ('organization', '0002_auto_20190512_1919'),
    ]

    operations = [
        migrations.AlterField(
            model_name='procedure',
            name='current_state',
            field=river.models.fields.state.StateField(blank=True, null=True, on_delete=django.db.models.deletion.CASCADE, related_name='rnc2a0dc9cd27e4f9383979698d883a495', to='river.State'),
        ),
    ]

Do you think this is related to this issue or do you think a new one should be created?

Thanks

javrasya commented 5 years ago

@superandrew , I think I know why this is happening and it is a bug in the place where this is logged. It is not affecting anything. Just logging part is buggy. Please ignore it until I fix and release it.

https://github.com/javrasya/django-river/blob/master/river/apps.py#L21

worflow_registry.workflow is a map of lists. It should be flattened and then looped.

javrasya commented 5 years ago

I created a PR @superandrew . I am waiting for the build to see if that breaks anything

javrasya commented 5 years ago

I even published it. Can you try django-river v1.0.1 @superandrew .

superandrew commented 5 years ago

thanks @javrasya !

I think the problem has been solved partially, but not completely. django-river==1.0.0

ipdbackend on  release/1.1.2 [$!] via ipaddi-backend took 1m 44s 
➜ manage.py makemigrations        
140252405073224 field doesn't seem have any transition approval meta in database. You should create it's TransitionApprovalMeta
Migrations for 'organization':
  ipdbackend/organization/migrations/0004_auto_20190701_1310.py
    - Alter field current_state on procedure

ipdbackend on  release/1.1.2 [$!?] via ipaddi-backend took 3s 
➜ manage.py makemigrations
140333496797320 field doesn't seem have any transition approval meta in database. You should create it's TransitionApprovalMeta
Migrations for 'organization':
  ipdbackend/organization/migrations/0005_auto_20190701_1310.py
    - Alter field current_state on procedure

django-river==1.0.1

ipdbackend on  release/1.1.2 [$!?] via ipaddi-backend took 2s 
➜ manage.py makemigrations       
Migrations for 'organization':
  ipdbackend/organization/migrations/0006_auto_20190701_1313.py
    - Alter field current_state on procedure

ipdbackend on  release/1.1.2 [$!?] via ipaddi-backend took 2s 
➜ manage.py makemigrations
Migrations for 'organization':
  ipdbackend/organization/migrations/0007_auto_20190701_1313.py
    - Alter field current_state on procedure

What happens is, despite not being warned, a new migration is generated every time I run manage.py makemigrations.

Is this normal?

Thanks

javrasya commented 5 years ago

It doesn't seem to be normal 😄

Can you share those migration file contents? So I can have some idea maybe 🤔

javrasya commented 5 years ago

I managed to reproduce that. I will have a look if I can understand why this is happening.

javrasya commented 5 years ago

Here I created another issue for that. Let's discuss it over there. Please don't use this issue. If you have another issue feel free to create a new one for it.

https://github.com/javrasya/django-river/issues/77