text: 'use strict';
  
  /**
   * update_upsert_multi.js
   *
   * Tests updates that specify both multi=true and upsert=true.
   * The 'insert' state uses a query that will match no documents, causing an upsert.
   * The 'update' state uses a query that will match one or more documents, causing a multi-update.
   * Both states use { multi: true, upsert: true }, but only one option will ever take effect,
   * depending on whether 0 or more than 0 documents match the query.
   */
  var $config = (function() {
  
      var states = {
          insert: function insert(db, collName) {
              var query, update, options;
              var res = db[collName].update(
                  // The counter ensures that the query will not match any existing document.
                  query = { tid: this.tid, i: this.counter++ },
                  update = { $inc: { n: 1 } },
                  options = { multi: true, upsert: true }
              );
              var debugDoc = tojson({ query: query, update: update, options: options, result: res });
              assertWhenOwnColl.eq(1, res.nUpserted, debugDoc);
              assertWhenOwnColl.eq(0, res.nMatched, debugDoc);
              if (db.getMongo().writeMode() === 'commands') {
                  assertWhenOwnColl.eq(0, res.nModified, debugDoc);
              }
          },
  
          update: function update(db, collName) {
              var res = db[collName].update(
                  // This query will match an existing document, since the 'insert' state
                  // always runs first.
                  { tid: this.tid },
                  { $inc: { n: 1 } },
                  { multi: true, upsert: true }
              );
  
              assertWhenOwnColl.eq(0, res.nUpserted, tojson(res));
              assertWhenOwnColl.lte(1, res.nMatched, tojson(res));
              if (db.getMongo().writeMode() === 'commands') {
                  assertWhenOwnColl.eq(res.nMatched, res.nModified, tojson(res));
              }
          },
  
          assertConsistency: function assertConsistency(db, collName) {
              // Since each update operation either:
              //  - inserts a new doc { tid: tid, i: counter++, n: 0 }
              //  - updates any doc matching { tid: tid } with { $inc: { n: 1 } }
              // Then within each tid, as you walk from lower to higher values of i,
              // the value of n should be non-increasing. (This should be true
              // because docs with lower i are newer, so they have had fewer
              // opportunities to have n incremented.)
              var prevN = Infinity;
              db[collName].find({ tid: this.tid }).sort({ i: 1 }).forEach(function(doc) {
                  assertWhenOwnColl.gte(prevN, doc.n);
                  prevN = doc.n;
              });
          }
      };
  
      var transitions = {
          insert: { update: 0.875, assertConsistency: 0.125 },
          update: { insert: 0.875, assertConsistency: 0.125 },
          assertConsistency: { insert: 0.5, update: 0.5 }
      };
  
      function setup(db, collName, cluster) {
          assertAlways.commandWorked(db[collName].ensureIndex({ tid: 1, i: 1 }));
      }
  
      return {
          threadCount: 10,
          iterations: 20,
          states: states,
          startState: 'insert',
          transitions: transitions,
          data: { counter: 0 },
          setup: setup
      };
  
  })();
  