2017-02-21 47 views
6

mieć baza danych dostępna w scalatest z ewolucji Używam tego rozszerzenia domyślnie PlaySpec zainspirowany this SO question:zabaw testy z bazy danych: „Zbyt wiele połączeń”

trait ResetDbSpec extends PlaySpec with BeforeAndAfterAll { 
    lazy val appBuilder = new GuiceApplicationBuilder() 
    lazy val injector = appBuilder.injector() 
    lazy val databaseApi = injector.instanceOf[DBApi] 

    override def beforeAll() = { 
    Evolutions.applyEvolutions(databaseApi.database("default")) 
    } 

    override def afterAll() = { 
    Evolutions.cleanupEvolutions(databaseApi.database("default")) 
    databaseApi.database("default").shutdown() 
    } 
} 

Dotyczy ewolucje bazy danych podczas uruchamiania pakiet, i przywraca je, gdy pakiet się kończy. Test wtedy wygląda

class ProjectsSpec extends ResetDbSpec with OneAppPerSuite { ... 

Po dodaniu więcej testów tak, uderzę punkt, w którym pewne testy, które uda kiedy uruchomić je w spokoju, nie powiedzie się ten błąd:

com.mysql.jdbc.exceptions.jdbc4.MySQLNonTransientConnectionException: Data source rejected establishment of connection, message from server: "Too many connections"

Jak można zobaczyć w powyższym kodzie, próbowałem dodać linię

databaseApi.database("default").shutdown() 

w afterAll() złagodzić, ale to nie miało żadnego wpływu. Próbowałem nie uruchamiać testów równolegle, ale bez efektu. Gdzie jest to, że otwieram połączenia DB bez ich zamykania i gdzie powinienem zadzwonić pod numer shutdown()?

N.B. Używam Play 2.5.10 i Slick 3.1.

+0

Czy aplikacja próbuje zachować więcej połączeń w puli niż baza danych pozwoli na otwarcie? –

+0

@MichaelZajac Jak mogę to sprawdzić? – JulienD

+0

Czy zmiana "lazy val databaseApi' na" def databaseApi' pomaga? W przeciwnym razie możesz sprawdzić https://www.playframework.com/documentation/2.5.x/SettingsJDBC, aby dostosować maksymalny rozmiar puli. Podobnie jak w @MichaelZajac powiedział, można sprawdzić konfigurację lokalnej bazy danych, aby zobaczyć, ile połączeń pozwala. – Eric

Odpowiedz

1

mam dużo testów (około 500), a ja nie rozumiem tego błędu, z tą tylko różnicą, że mają z kodem jest to, że mogę dodać

databaseApi.database("default").getConnection().close() 

i

Play.stop(fakeApplication) 

do testów integracji.

Daj mi znać, jeśli coś zmieni.

+0

Niestety nie :(. Jak tylko wezwę 'databaseApi' w BeforeAll lub AfterAll dostaję błąd (np. Leniwy val jest oceniony) .Może źle mnie zrozumiałem, dodałem te dwie linie, które sugerujesz w' afterAll() 'Mam tylko ~ 120 testów.Być może MySQL, lub zręczny sterownik do tego, jest po to, by coś w tym znaleźć. – JulienD

+0

Nie Myślę, że dobrze zrozumiałeś. Jeśli to może pomóc, używam PostgreSQL i nie zmieniam nic z bazy danych, slick lub konfiguracji hikariCP (przynajmniej dla testów) – Simon

1

Chociaż nie odpowiada temu, co dzieje się z nieszczelności połączeń, ale w końcu udało się włamać wokół to:

  1. Dodaj jdbc wam libraryDependencies, nawet jeśli Play-Slick FAQ mówi nie robić to:

    # build.sbt 
    libraryDependencies += jdbc 
    

    Uruchom ponownie sbt, aby uwzględnić zmiany. W IntelliJ również chcesz odświeżyć projekt.

  2. Wyłącz jdbc moduł, który jest w konflikcie z Play-zręczny (punktów: this SO answer):

    # application.conf 
    play.modules.disabled += "play.api.db.DBModule" 
    

    W tym samym miejscu należy już skonfigurowany coś podobnego

    slick { 
        dbs { 
        default { 
         driver = "slick.driver.MySQLDriver$" 
         db.driver = "com.mysql.jdbc.Driver" 
         db.url = "jdbc:mysql://localhost/test" 
         db.user = "sa" 
         db.password = "" 
        } 
        } 
    } 
    
  3. Teraz możesz użyć play.api.db.Databases z jdbc i jego metody withDatabase, aby uruchomić ewolucję s.

    import org.scalatest.BeforeAndAfterAll 
    import org.scalatestplus.play.PlaySpec 
    import play.api.db.{Database, Databases} 
    import play.api.db.evolutions.Evolutions 
    
    
    trait ResetDbSpec extends PlaySpec with BeforeAndAfterAll { 
    
        /** 
        * Here we use Databases.withDatabase to run evolutions without leaking connections. 
        * It slows down the tests considerably, though. 
        */ 
    
        private def withTestDatabase[T](block: Database => T) = { 
        Databases.withDatabase(
         driver = "com.mysql.jdbc.Driver", 
         url = "jdbc:mysql://localhost/test", 
         name = "default", 
         config = Map(
         "username" -> "sa", 
         "password" -> "" 
        ) 
        )(block) 
        } 
    
        override def beforeAll() = { 
        withTestDatabase { database => 
         Evolutions.applyEvolutions(database) 
        } 
        } 
    
        override def afterAll() = { 
        withTestDatabase { database => 
         Evolutions.cleanupEvolutions(database) 
        } 
        } 
    
    } 
    
  4. Wreszcie, testy połączeń wymagających resetu db tak:

    class MySpec extends ResetDbSpec {...} 
    

Oczywiście to jest do bani powtarzając ten config zarówno w "application.test.conf" iw withDatabase() plus łączy dwa różne API, nie mówiąc o wydajności. Dodaje także to przed i po każdym pakiecie, co jest denerwujące:

[info] application - Creating Pool for datasource 'default'
[info] application - Shutting down connection pool.

Jeśli ktoś ma lepszą sugestię, proszę poprawić tę odpowiedź! Walczę od miesięcy.