1

J'essaie de tester des parties de mon code pour des conditions de course. Le problème que j'avais était lié à des validations d'unicité, qui, comme il s'avère, n'est pas à l'abri des conditions de course dans les rails. Je crois que je serai en mesure de résoudre le problème, mais je ne suis pas sûr de savoir comment tester ma solution.Test des rails pour les conditions de course, et nettoyage après

Le plus proche que je suis venu est le suivant (inspiré par: http://blog.arkency.com/2015/09/testing-race-conditions/):

test "Can't create duplicate keys with same value and keyboard" do 
    assert_equal(5, ActiveRecord::Base.connection.pool.size) 
    begin 
    concurrency_level = 4 
    keyboard = create :keyboard 
    should_wait = true 

    statuses = {} 

    threads = Array.new(concurrency_level) do |i| 
     Thread.new do 
     true while should_wait 
     begin 
      # Unique validation for key values exists scoped to keyboard 
      key = keyboard.keys.new(value: 'a') 
      statuses[i] = key.save 
     rescue ActiveRecord::RecordNotUnique 
      statuses[i] = false 
     end 
     end 
    end 
    should_wait = false 
    threads.each(&:join) 

    assert_equal(1, keyboard.keys.count) 
    assert_equal(1, statuses.count { |_k, v| v }) 
    assert_equal(3, statuses.count { |_k, v| !v }) 
    ensure 
    ActiveRecord::Base.connection_pool.disconnect! 
    end 
end 

Le code ci-dessus est structuré exactement comme le mien, mais les modèles ont changé pour être plus général.

Le test lui-même semble fonctionner correctement. Cependant, les clés créées dans les tests ne sont pas supprimées par la suite. J'utilise DatabaseCleaner et j'ai essayé toutes les différentes stratégies. En outre, parfois, je reçois un problème de dépendance circulaire pour la clé constante. Je ne sais pas pourquoi, mais je suppose que c'est dû à ne pas être thread safe dans ruby?

Y a-t-il un meilleur moyen de résoudre mon problème? Comme je l'ai indiqué ci-dessus, j'ai eu quelques problèmes différents avec ceci, et je pense que cela devrait être un problème suffisamment commun pour que de bonnes normes de test existent.

Répondre

1

Quelques choses:

1) Probablement mon ignorance, mais la ligne true while should_wait me semble mal à. Quelque chose de plus comme while should_wait do semble plus comme ce que vous avez l'intention. Vous appelez également le pod.save, ce qui n'a pas de sens, donc je suppose que ce n'est pas exactement le code que vous utilisez.

2) Je m'attendrais à ce que le programme de nettoyage de base de données fonctionne, car je pense que si vous utilisez la stratégie de "troncature", il passera et tronquera chaque table lorsque le test sera exécuté. Mon supposition de cul sauvage est que vous l'avez configuré pour courir seulement pour des tests d'intégration et ceci est un test unitaire, ou quelque chose comme ça. Si ce n'est pas le cas, essayez d'appeler DatabaseCleaner.truncate (ou de le faire explicitement) à la fin du test et voyez si cela fonctionne.

3) Pouvez-vous résoudre le problème avec un index unique dans votre base de données? Cela supprime la nécessité de ce test, car vous n'avez plus qu'à faire confiance à votre base de données. Lorsque vous obtenez une valeur non unique, vous pouvez gérer cela de manière non-validation dans votre code. Beaucoup plus rapide aussi, car vous n'avez pas besoin de faire l'appel supplémentaire de sql chaque fois que vous économisez.

4) Impossible de savoir à partir des informations fournies pourquoi vous obtenez le problème de dépendance circulaire. J'ai déjà eu ce problème et j'ai fait un puts caller en haut du fichier pour essayer de diagnostiquer.

+0

1) La boucle est juste un bidouillage pour s'assurer que tous les threads démarrent en même temps. Vous aviez raison concernant "pod.save", je l'ai édité pour correspondre à mon exemple. 2) Je vais devoir essayer ça. Je pensais que je l'ai configuré pour nettoyer après chaque test, mais vous pourriez très bien avoir raison. 3) Oui, c'est la solution que j'utilise. Et vous avez raison de dire que je peux probablement faire confiance à la DB pour le gérer correctement. J'ai quelques autres scénarios qui pourraient être un peu plus difficiles à résoudre, donc une façon générale de tester les conditions de course serait encore bonne. –