There's been an intermittent test failure in the Field module lately. Here's an instance (hopefully the test won't get erased with a retest):
http://qa.drupal.org/pifr/test/109119

The test failure is:

Field form tests (FieldFormTestCase) [Field API] 236 1 0

Widgets are displayed in the correct order Other field.test 1458 FieldFormTestCase->testFieldFormJSAddMore()

Here's the code that is generating the failure -- it uses some random numbers to generate weights, then tests that they are in the right order -- I suspect that in some rare cases, something strange is happening with the random numbers so that the test is failing:

    for ($delta = 0; $delta <= $delta_range; $delta++) {
      // Assign unique random weights.
      do {
        $weight = mt_rand(-$delta_range, $delta_range);
      } while (in_array($weight, $weights));
      $value = mt_rand(1, 127);
      $edit["$this->field_name[$langcode][$delta][value]"] = $value;
      $edit["$this->field_name[$langcode][$delta][_weight]"] = $weight;
      // We'll need three slightly different formats to check the values.
      $values[$delta] = $value;
      $weights[$delta] = $weight;
      $field_values[$weight]['value'] = (string) $value;
      $pattern[$weight] = "<input [^>]*value=\"$value\" [^>]*";
    }
    // Press 'add more' button through AJAX, and place the expected HTML result
    // as the tested content.
    $commands = $this->drupalPostAJAX(NULL, $edit, $this->field_name . '_add_more');
    $this->content = $commands[1]['data'];

    for ($delta = 0; $delta <= $delta_range; $delta++) {
      $this->assertFieldByName("$this->field_name[$langcode][$delta][value]", $values[$delta], "Widget $delta is displayed and has the right value");
      $this->assertFieldByName("$this->field_name[$langcode][$delta][_weight]", $weights[$delta], "Widget $delta has the right weight");
    }
    ksort($pattern);
    $pattern = implode('.*', array_values($pattern));
    $this->assertPattern("|$pattern|s", 'Widgets are displayed in the correct order');

It's the last line here where the failure happens.

Comments

carlos8f’s picture

subscribing

rfay’s picture

subscribe

jhodgdon’s picture

Looking at this, I'm wondering if it's a problem with duplications in the $value values.

That is to say, the test line that's failing is basically testing that a regexp like
input value="val1" .* input value="val2" .* input val="val3" ...
exists on the page, wehre val1, val2, etc. are random integers. But what if val6 and val20 are the same, for instance? Maybe the regexp when it gets to val6 will skip all the way to val20 and then the rest of the regexp will fail? I'm not all up on regexp greediness, so I'm not sure if that would happen or not (or if I'm making sense).

Suggested solution (if that's the problem) would be to do something with values like what is being done with the weights [i.e. make sure they are all different].

yched’s picture

Status: Active » Needs review
StatusFileSize
new1.24 KB

jhodgdon is right, failure happens with the greediness of the regexp when some values are the same.

- added a for (10 times) around the tested part, ran the test 5 times: no failure
- changed the test so that values are always the same, ran the test once: 10 failures

Patch makes sure that the values are always different

jhodgdon’s picture

yched: this looks like it would work, but perhaps it would be better to have the "unique weights" and "unique values" loops separate instead of put into one loop together?

jhodgdon’s picture

Status: Needs review » Needs work

Also, in the first hunk you forgot to remove the $value call that was there, so it will be reset after you carefully made sure it was unique:

      do {
         $weight = mt_rand(-$delta_range, $delta_range);
-      } while (in_array($weight, $weights));
+        $value = mt_rand(1, 127);
+      } while (in_array($weight, $weights) || in_array($value, $values));
       $value = mt_rand(1, 127);
yched’s picture

Status: Needs work » Needs review
StatusFileSize
new1.7 KB

True. Fixed.

jhodgdon’s picture

That looks more reasonable. :)

Let's make sure the test bot passes it (at least once), and then it's probably good for RTBC.

carlos8f’s picture

Status: Needs review » Reviewed & tested by the community

Fix looks correct... bot will set it back to CNW if it fails.

webchick’s picture

Does this have to be random at all..?

carlos8f’s picture

Doesn't *have* to be, but it makes sense since we are asserting that anything within those ranges is valid.

yched’s picture

values don't really have to be random - but are better random since we test with a regexp.
weights have to be random: this is what we are testing

jhodgdon’s picture

The values could probably just be generated with a $i++ type thing to make them unique, instead of random.

webchick’s picture

Status: Reviewed & tested by the community » Needs work

Could we do that instead? The code as written is more difficult to read than what's in HEAD, and if we don't need randomness, I'd prefer not to use it. Randomness is almost always a recipe for "random test failures".

carlos8f’s picture

Randomness in tests is a Good Thing(tm) if it causes failures that allow you to find a real bug. But in this case there's no real bug :) I think this is still fine to be RTBC.

jhodgdon’s picture

I am not sure I agree with you carlos8f. Randomness like this causes intermittent test failures that are not reproducible and cause people to pull their hair out. If these failures are not detected when the test is first committed (like this one), they occur rancomly, breaking the test bot, later on.

I just got bitten by this failure, just now, on a totally unrelated patch (a doc-only patch), though, so I hope we can get this fixed one way or another.

jhodgdon’s picture

Or to put it another way, maybe randomness is a good thing, but if you use it as a big feature of your test, maybe you should have a loop in your test that runs the random section several times. This would verify that it's really passing based on several runs at the randomness, rather than relying on the fact that it worked when you first submitted the patch.

PHP and other programming languages don't really have "random" numbers -- they just have pseudo-random numbers, which will come out the same every time, given the same random seed. This test was not failing much until recently (at least, so I believe). Maybe if it had had a loop in it, the failure would have been detected and fixed before the patch was initially committed?

carlos8f’s picture

Sometimes tests fail only when a bot is run under high concurrency, sometimes they fail due to being on 32 bit hardware, sometimes a version of PCRE or libxml causes a fail. Sometimes tests get committed that aren't even deterministic.

There are a lot of reasons why test fails wouldn't be caught before initial commit. Randomness is often useful to catch bugs that happen when you venture outside of 'foo' and 'bar', but when using randomness you should be sure that you assert correctly. So I wouldn't discourage the use of randomness based on a few incorrect assertions.

webchick’s picture

Status: Needs work » Fixed

Well, since this once again broke HEAD and stalled out testbot, I decided to commit #7 to HEAD.

While I was going through I noticed that there are actually lots of uses of mt_rand in field.test, including this same do { ... } while pattern used elsewhere. So cleaning all that up would likely be the subject of another issue anyway.

Thanks for the fix!

Status: Fixed » Closed (fixed)

Automatically closed -- issue fixed for 2 weeks with no activity.