mongodbscalamongodb-scala

Mongodb Scala Driver: How to test an error?


I am writing a sort of integration testing using Scala driver for Mongodb (1.1.1).

I have a simple insert query and I am able to manage it using either a future or observer in this way:

// with observer
driver.myCollection.insertOne(doc).subscribe(new Observer[Completed] {
      override def onNext(result: Completed) = /* do something */
      override def onComplete() = /* do something */
      override def onError(e: Throwable) = /* do something */
    })

// with future
val f = driver.myCollection.insertOne(doc).toFuture()
f onComplete {
      case Success(successMsg) => /* do something */
      case Failure(failureMsg) => /* do something */
    }
  }

How can I test onError in the Observer and/or Failure in the Future? How can I trigger this condition?

At the moment I am using Mongodb Embedded (flapdoodle).

If I shutdown the Mongodb at the beginning of the test, I get a timeout which doesn't look related to that errors.

UPDATE

I have added WriteConcern to the collection:

database.getCollection(myCollection).withWriteConcern(WriteConcern.ACKNOWLEDGED)

but it doesn't change anything.

Are the errors returned by futures/observers including timeout errors (caused when the db or network are down for some reasons)?


Solution

  • One way to materialize an error would be creation of unique index on the collection as is described here: https://docs.mongodb.com/manual/core/index-unique/ When you have the unique index created you then can insert an item and then try to insert it once again. That way you will get an error.

    Regarding your question if the timeout thrown also counts in onError the answer is yes, it counts. Here is a snippet of my code:

    def findByTitle(title:String)(implicit ec:ExecutionContext):Future[Option[Document]] = {
        val collection = db.getCollection("items")
        collection.find(equal("title", title))
          .toFuture()
          .recoverWith{case e:Throwable => {println("Simulated error happened"); println(e); Future.failed(e)}}
          .map{seq => if(seq.isEmpty) None else Some(seq.head)}
      }
    

    Before clicking a button on UI which triggers this method call I have stopped the MongoDB service with command line command net stop MongoDB (I am on Windows). Then I triggered the action and after a while when timeout triggered I saw this in my console:

    [info] p.c.s.NettyServer - Listening for HTTP on /0:0:0:0:0:0:0:0:9000
    
    Server started, use Alt+D to stop
    
    [info] play.api.Play - Application started (Dev)
    Simulated error happened
    com.mongodb.MongoTimeoutException: Timed out after 30000 ms while waiting for a server that matches ReadPreferenceServerSelector{readPreference=primary}. Client view of cluster state is {type=UNKNOWN, servers=[{address=localhost:27017, type=UNKNOWN, state=CONNECTING, exception={com.mongodb.MongoException: java.io.IOException: The remote computer refused the network connection.
    }, caused by {java.io.IOException: The remote computer refused the network connection.
    }}]
    [error] application - 
    ....
    

    So as you can see timeout is also handled, it should be since MongoTimeoutException is a Throwable.