socialgekon.com
  • Tärkein
  • Muu
  • Web-Käyttöliittymä
  • Työn Tulevaisuus
  • Suunnittelu
Taustaa

Aikaleiman katkaisu: Ruby on Rails ActiveRecord Tale

Testien on tarkoitus auttaa pitämään sovellukset hilseilemästä. Mutta joskus testeistä voi tulla hiutaleita - jopa suorimmatkin. Näin pääset ongelmalliseen testiin a Ruby on Rails PostgreSQL: n tukema sovellus ja mitä paljastimme.

Halusimme tarkistaa, että tietty liiketoimintalogiikka (jota kutsutaan menetelmällä perform) ei muuta calendar malli (esimerkki Calendar, Ruby on Rails ActiveRecord -malliluokasta), joten kirjoitimme:

let(:calendar) { create(:calendar) } specify do expect do perform # call the business action calendar.reload end .not_to change(calendar, :attributes) end

Tämä oli ohi yhdessä kehitysympäristössä (MacOS), mutta se lähes aina epäonnistui CI: ssä (Linux).



Onneksi onnistuimme toistamaan sen toisessa kehitysympäristössä (Linux), jossa se epäonnistui viestillä:

expected `Calendar#attributes` not to have changed, but did change from {'calendar_auth_id'=>8, 'created_at'=>2020-01-02 13:36:22.459149334 +0000, 'enabled'=>false, 'events_...t_sync_token'=>nil, 'title'=>nil, 'updated_at'=>2020-01-02 13:36:22.459149334 +0000, 'user_id'=>100} to { 'calendar_auth_id'=>8, 'created_at'=>2020-01-02 13:36:22.459149000 +0000, 'enabled'=>false, 'events_...t_sync_token'=>nil, 'title'=>nil, 'updated_at'=>2020-01-02 13:36:22.459149000 +0000, 'user_id'=>100}

Näetkö jotain hämärää?

Tutkimus

Tarkemmin tarkastellessamme huomasimme, että created_at ja updated_at aikaleimoja muutettiin hieman expect: n sisällä lohko:

{'created_at'=>2020-01-02 13:36:22.459149334 +0000, 'updated_at'=>2020-01-02 13:36:22.459149334 +0000} {'created_at'=>2020-01-02 13:36:22.459149000 +0000, 'updated_at'=>2020-01-02 13:36:22.459149000 +0000}

Sekuntien murto-osa katkaistiin siten, että 13:36:22.459149334 tuli 13:36:22.459149000.

Olimme varmoja, että perform ei päivittänyt calendar objektin, joten muodostimme hypoteesin, jonka mukaan tietokanta katkaisi aikaleimat. Tämän testaamiseksi käytimme edistyneintä tunnettua virheenkorjaustekniikkaa, ts. laittaa virheenkorjauksen :

let(:calendar) { create(:calendar) } specify do expect do puts 'before perform: #{calendar.created_at.to_f}' perform puts 'after perform: #{calendar.created_at.to_f}' calendar.reload puts 'after reload: #{calendar.created_at.to_f}' end .not_to change(calendar, :attributes) end

Mutta katkaisu ei ollut näkyvissä tulosteessa:

before perform: 1577983568.550754 after perform: 1577983568.550754 after reload: 1577983568.550754

Tämä oli varsin yllättävää - lisävaruste #created_at olisi pitänyt olla sama arvo kuin attribuutin hash-arvo attributes['created_at'] Varmistaaksemme, että tulostimme saman arvon kuin väitteessä, muutimme tapaa, jolla pääsimme created_at

Sen sijaan, että käyttäisimme lisävarustetta calendar.created_at.to_f, vaihdoimme sen hakemiseen suoraan hash-määritteistä: calendar.attributes['created_at'].to_f. Epäilyksemme calendar.reload vahvistettiin!

before perform: 1577985089.0547702 after perform: 1577985089.0547702 after reload: 1577985089.05477

Kuten näette, soittaminen perform ei muuttunut created_at, mutta reload teki.

Varmista, että muutosta ei tapahtunut toisessa calendar -tapauksessa ja sitten pelastettuna teimme vielä yhden kokeen. Ladasimme uudelleen calendar ennen testiä:

let(:calendar) { create(:calendar).reload } specify do expect do perform calendar.reload end .not_to change(calendar, :attributes) end

Se teki testistä vihreän.

Korjaus

Koska tiedämme, että tietokanta katkaisee aikaleimamme ja epäonnistuu testeissämme, päätimme estää katkaisun. Luomme DateTime pyöristää sen kokonaisiin sekunteihin. Sitten käytimme tätä objektia asettamaan Railsin aktiivisen tietueen aikaleimat nimenomaisesti. Tämä muutos vahvisti ja vakautti testit:

let(:time) { 1.day.ago.round } let(:calendar) { create(:calendar, created_at: time, updated_at: time) } specify do expect do perform calendar.reload end .not_to change(calendar, :attributes) end

Syy

Miksi näin tapahtui? Aktiivisen tietueen aikaleimat ovat kiskojen asettamat ’ActiveRecord::Timestamp moduuli käyttämällä Time.now . Time tarkkuus on Käyttöjärjestelmästä riippuvainen ja kuten asiakirjoissa todetaan, voi sisältää murto-sekunteja .

Testasimme Time.now päätöslauselma MacOS: ssa ja Linuxissa komentosarjalla, joka laskee murto-osan pituuksien taajuudet:

pry> 10000.times.map { Time.now.to_f.to_s.match(/.(d+)/)[1].size }.group_bya.map [k, v.count].to_h # MacOS => {6=>6581, 7=>2682, 5=>662, 4=>67, 3=>7, 2=>1} # Linux => {6=>2399, 7=>7300, 5=>266, 4=>32, 3=>3}

Kuten näette, noin 70%: lla Linuxin aikaleimoista oli tarkkuus seitsemän numeroa desimaalin jälkeen, kun taas MacOS: ssa vain 25%. Tästä syystä testit läpäisivät suurimman osan ajasta MacOS: ssä ja epäonnistuivat suurimman osan ajasta Linuxissa. Olet ehkä huomannut, että testilähdöllä oli yhdeksän numeron tarkkuus - se johtuu RSpecista käyttää Time#nsec muotoilla aikalähtö.

Kun Rails-mallit tallennetaan tietokantaan, kaikki niiden aikaleimat tallennetaan PostgreSQL: n tyypillä nimeltä timestamp without time zone, joka on mikrosekunnin tarkkuus - eli kuusi numeroa desimaalin jälkeen. Joten kun 1577987974.6472975 lähetetään PostgreSQL: ään, se katkaisee murto-osan viimeisen numeron ja tallentaa sen sijaan 1577987974.647297

Kysymykset

On edelleen kysymys miksi calendar.created_at ei ladattu uudelleen, kun soitimme calendar.reload, vaikka calendar.attributes['created_at'] ladattiin uudelleen.

Myös tulokset Time tarkkuustesti ovat hieman yllättäviä. Odotimme, että MacOS: lla suurin tarkkuus on kuusi. Emme tiedä miksi joskus siinä on seitsemän numeroa. Yllätti meidät enemmän viimeisten numeroiden arvon jakautuminen:

pry> 10000.times.map { Time.now}.map t.to_f.to_s.match(/.(d+)/)[1] .select.group_bye.map [k, v.size].to_h # MacOS => {'9'=>536, '1'=>555, '2'=>778, '8'=>807} # Linux => {'5'=>981, '1'=>311, '3'=>1039, '9'=>309, '8'=>989, '6'=>1031, '2'=>979, '7'=>966, '4'=>978}

Kuten näette, MacOS: n seitsemäs numero on aina 1, 2, 8 tai 9.

Jos tiedät vastauksen jompaankumpaan näistä kysymyksistä, jaa selitys meille.

Tulevaisuus

Se, että Ruby on Rails ” Aktiivinen ennätys Aikaleimat luodaan sovelluspuolelle voivat myös vahingoittaa, kun näitä aikaleimoja käytetään tietokantaan tallennettujen tapahtumien luotettavaan ja tarkkaan järjestämiseen. Koska sovelluspalvelimen kellot voidaan synkronoida, tapahtumat järjestetään created_at voivat näkyä eri järjestyksessä kuin ne todellisuudessa tapahtuivat. Saada luotettavampi käyttäytyminen , olisi parempi antaa tietokantapalvelimen hoitaa aikaleimat (esim. PostgreSQL: t now() ).

Se on kuitenkin toisen artikkelin arvoinen tarina.


Erityiskiitokset Gabriele Renzi tämän artikkelin luomisessa.

Perustietojen ymmärtäminen

Mikä on ActiveRecord Ruby-palvelussa?

ActiveRecord on objektisuhdekartoituskirjasto, jonka tarjoaa Ruby on Rails. Sen avulla voit säilyttää objekteja tietokannassa, hakea sitten tallennettuja tietoja ja välittää objekteja.

Mikä on Active Record -toteutus?

Active Record on yritysarkkitehtuurimalli, jota käytetään muistin sisäisten objektien säilyttämiseen relaatiotietokannoissa. Ruby on Rails -toteutuksessa ActiveRecord seuraa muutoksia Rails-mallin määritteisiin. Kun malli on tallennettu, ActiveRecord lähettää muutokset ja tarvittavat aikaleimat tietokantaan.

Miksi aikaleima on tärkeä?

ActiveRecord tallentaa oletusarvoisesti kaksi aikaleimaa: created_at (aika, jolloin malli tallennettiin ensimmäisen kerran) ja updated_at (aika, jolloin malli viimeksi tallennettiin). Ne tarjoavat perustarkastusominaisuudet ja antavat sovellusten lajitella malleja uusimmista tai viimeisimmistä päivitetyistä.

Mikä on aikaleima PostgreSQL: ssä?

Aikaleima on PostgreSQL-tietotyyppi, joka tallentaa sekä päivämäärän että kellonajan. Sillä on yhden mikrosekunnin tarkkuus ja tarkkuus, mikä tarkoittaa, että se pitää sekuntien murto-osan jopa kuuteen numeroon.

Mitä tietokantaa Ruby on Rails käyttää?

Ruby on Rails antaa kehittäjille mahdollisuuden käyttää suurinta osaa suosituista tietokannoista. Oletuksena Ruby on Rails käyttää ActiveRecord-kirjastoa, joka tukee DB2, Firebird, FrontBase, MySQL, OpenBase, Oracle, PostgreSQL, SQLite, Microsoft SQL Server ja Sybase.

Mielen silmä - katsaus datan visualisointipsykologiaan

Ux-Suunnittelu

Mielen silmä - katsaus datan visualisointipsykologiaan
Tekoälyn nykyisyys ja tulevaisuus suunnittelussa (infografiikan kanssa)

Tekoälyn nykyisyys ja tulevaisuus suunnittelussa (infografiikan kanssa)

Ux-Suunnittelu

Suosittu Viestiä
Elixir-ohjelmointikielen käytön aloittaminen
Elixir-ohjelmointikielen käytön aloittaminen
Heuristinen analyysi UX: lle - Kuinka suorittaa käytettävyyden arviointi
Heuristinen analyysi UX: lle - Kuinka suorittaa käytettävyyden arviointi
Tietorakenteen periaatteet mobiililaitteille (infografiikan kanssa)
Tietorakenteen periaatteet mobiililaitteille (infografiikan kanssa)
Reagoiva suunnittelu ei riitä, tarvitsemme reagoivaa suorituskykyä
Reagoiva suunnittelu ei riitä, tarvitsemme reagoivaa suorituskykyä
Google-kuvat ja tietosuoja: Näin pidät valokuvasi turvassa
Google-kuvat ja tietosuoja: Näin pidät valokuvasi turvassa
 
Kuinka käyttää Google Kuvia iPhonessa kuvien varmuuskopioimiseen, tallentamiseen ja jakamiseen
Kuinka käyttää Google Kuvia iPhonessa kuvien varmuuskopioimiseen, tallentamiseen ja jakamiseen
Ansiosopimukset: Rakenteet neuvottelujen kuolleiden pisteiden rikkomiseksi
Ansiosopimukset: Rakenteet neuvottelujen kuolleiden pisteiden rikkomiseksi
Koneoppimisen numerotunnistus - nollasta sovellukseen
Koneoppimisen numerotunnistus - nollasta sovellukseen
Hinta on oikea - yleiskatsaus hinnoittelustrategiaan kuluttajayrityksille
Hinta on oikea - yleiskatsaus hinnoittelustrategiaan kuluttajayrityksille
Kuinka lisätä musiikkia Instagram-tarinaan tarroilla tai ilman
Kuinka lisätä musiikkia Instagram-tarinaan tarroilla tai ilman
Luokat
Tietojenkäsittely Ja TietokannatiOS-vinkkejäWeb-KäyttöliittymäTrenditProjektinhallintaKetteräAmmuntaOngelmien karttoittaminenElämäntapaTaustaa

© 2023 | Kaikki Oikeudet Pidätetään

socialgekon.com