66
SmokeTests Why you should try to burn down your production environment

SmokeTests

Embed Size (px)

Citation preview

SmokeTestsWhy you should try to burn down

your production environment

Sebastian ThoßChapter Lead Backend

Disclaimer

Agenda• Project Architecture

• Types Of Tests

• SmokeTests

• Server Architecture

• Questions & Answers

Project Architecture

"one hundred fifty-seven quinvigintillion, seven hundred eighty-six quattuorvigintillion, six hundred fifty-seven trevigintillion, seven hundred

forty-seven duovigintillion, three hundred forty unvigintillion, one hundred eighty-six vigintillion, (…) nine hundred forty-five quintillion, eight hundred

twenty-eight quadrillion, two hundred seventy trillion, eighty billion, …"

Webserver

Key-Value Store

Search

FURY Frontend FURY Backend

FURY Components

Webserver

Key-Value Store

Search

FURY Frontend FURY Backend

Legacy RDBMSLegacy System Session Storage

Collect & Export

K-VStore

Webserver

Key-Value Store

Search

FURY Frontend FURY Backend

Legacy RDBMSLegacy System

FURY Requests

200 OK

Session Storage

K-VStore

Webserver

Key-Value Store

Search

FURY Frontend FURY Backend

Legacy RDBMSLegacy System

Requests to Legacy System

404 NOT FOUND

Session Storage

K-VStore

Webserver

Key-Value Store

Search

FURY Frontend FURY Backend

Legacy RDBMSLegacy System

Requests to Legacy System

404 NOT FOUND

200 OK

Session Storage

K-VStore

More information on www.sebastianthoss.de

Types Of Tests

Test Pyramid

UNIT TESTS

Class 2

Class 3

Mock

Mock

Unit Tests

Class 1

Class 4

Test Pyramid

INTEGRATION TESTS

UNIT TESTS

Class 4Class 3

Integration Tests

Class 1 Class 2

Mock Mock

Test Pyramid

INTEGRATION TESTS

UNIT TESTS

100% CODE COVER

AGE

Test Pyramid

ACCEPTANCE TESTS

INTEGRATION TESTS

UNIT TESTS

Acceptance Tests

Class 1 Class 2

Class 3 Class 4

Test Pyramid

ACCEPTANCE TESTS

INTEGRATION TESTS

UNIT TESTS

?

SmokeTests

What are SmokeTests?

In computer programming and software testing, smoke testing is preliminary testing to reveal simple failures severe enough to reject a prospective software release. Source: https://en.wikipedia.org/wiki/Smoke_testing

What are SmokeTests?

SmokeTests should…• … be simple

• … be fast

• … test pages with optional parameters too

• … cover at least all URLs in google index

• … use a manual maintained list of URLs

How do SmokeTests work?

https://www.my-application.com/foo

<html><body>…</body></html>

TTFB: 65ms

HTTP 1.1/200 OK

SmokeTestClient

CI Server

Application to test

Production Server

How do SmokeTests work?

https://www.my-application.com/foo

<html><body>…</body></html>

TTFB: 320ms

HTTP 1.1/200 OK

SmokeTestClient

CI Server Production Server

Application to test

What should SmokeTests validate?

• Status code

• Time to first byte

• If body is provided

• Correct server

SmokeTests are NOT Acceptance Tests

SmokeTestClient

HTTP 1.1/200 OK

<html> <head> <title>Foo</title> <body> <div id="bar"><span>foobar</span></div> </body> </html>

namespace Kartenmacherei\Testing;

use PHPUnit_Framework_TestCase;

class SmokeTest extends PHPUnit_Framework_TestCase { /** * @dataProvider furyUrlProvider * * @param Url $url */ public function testFuryUrl(Url $url) { $result = $this->sendGetRequest($url);

$this->assertSame(200, $result->getStatusCode()); $this->assertNotEmpty($result->getBody()); $this->assertLessThanOrEqual(100, $result->getTimeToFirstByteInMilliseconds()); }

public function furyUrlProvider() { $urls = ['http://www.kartenmacherei.de', …]; $urlCollection = UrlCollection::fromStrings($urls);

return $urlCollection->asDataProviderArray($urlCollection); }

How to speed up SmokeTests?

Concurrent SmokeTests

SmokeTestClient

CI Server

Applicationto test

Production Server

https://www.my-application.com/baz

https://www.my-application.com/bar

https://www.my-application.com/foo

Concurrent SmokeTests

https://www.my-application.com/baz

https://www.my-application.com/bar

https://www.my-application.com/foo

TTFB: 34ms

SmokeTestClient

CI Server

Applicationto test

Production Server

Concurrent SmokeTests

https://www.my-application.com/foobaz

https://www.my-application.com/bar

https://www.my-application.com/foo

SmokeTestClient

CI Server

Applicationto test

Production Server

Concurrent SmokeTests

TTFB: 65ms

https://www.my-application.com/foobaz

https://www.my-application.com/bar

https://www.my-application.com/foo

SmokeTestClient

CI Server

Applicationto test

Production Server

Concurrent SmokeTestshttps://www.my-application.com/123

https://www.my-application.com/foobaz

https://www.my-application.com/bar

SmokeTestClient

CI Server

Applicationto test

Production Server

Concurrent SmokeTests

TTFB: 620ms

https://www.my-application.com/123

https://www.my-application.com/foobaz

https://www.my-application.com/bar

SmokeTestClient

CI Server

Applicationto test

Production Server

Source: http://www.ve7kfm.com/fcc-server.jpg

Let’s try to burn it down!

There is a package for SmokeTests

DjThossi/Smoke-Testing-PHP

DataProvider

Test

Application

HTTP Requests

HTTP Responses

PHPUnit

Call

Result[]

Result

class SmokeTest extends PHPUnit_Framework_TestCase { use SmokeTestTrait;

/** * @dataProvider myDataProvider */ public function testExample(Result $result) { $this->assertSuccess($result); $this->assertTimeToFirstByte(new TimeToFirstByte(100), $result); $this->assertBodyNotEmpty($result); $this->assertHeaderExists(Header::fromPrimitives(‘App-Server', ‘Fury’), $result); }

public function myDataProvider() { $urls = ['http://www.kartenmacherei.de', …]; $options = new SmokeTestOptions( UrlCollection::fromStrings($urls), new RequestTimeout(2), new FollowRedirects(true), new Concurrency(3), new BodyLength(500) );

return $this->runSmokeTests($options); }

class SmokeTest extends PHPUnit_Framework_TestCase { use SmokeTestTrait;

/** * @dataProvider myDataProvider */ public function testExample(Result $result) { $this->assertSuccess($result); $this->assertTimeToFirstByte(new TimeToFirstByte(100), $result); $this->assertBodyNotEmpty($result); $this->assertHeaderExists(Header::fromPrimitives(‘App-Server', ‘Fury’), $result); }

public function myDataProvider() { $urls = ['http://www.kartenmacherei.de', …]; $options = new SmokeTestOptions( UrlCollection::fromStrings($urls), new RequestTimeout(2), new FollowRedirects(true), new Concurrency(3), new BodyLength(500) );

return $this->runSmokeTests($options); }

class SmokeTest extends PHPUnit_Framework_TestCase { use SmokeTestTrait;

/** * @dataProvider myDataProvider */ public function testExample(Result $result) { $this->assertSuccess($result); $this->assertTimeToFirstByte(new TimeToFirstByte(100), $result); $this->assertBodyNotEmpty($result); $this->assertHeaderExists(Header::fromPrimitives(‘App-Server', ‘Fury’), $result); }

public function myDataProvider() { $urls = ['http://www.kartenmacherei.de', …]; $options = new SmokeTestOptions( UrlCollection::fromStrings($urls), new RequestTimeout(2), new FollowRedirects(true), new Concurrency(3), new BodyLength(500) );

return $this->runSmokeTests($options); }

class SmokeTest extends PHPUnit_Framework_TestCase { use SmokeTestTrait;

/** * @dataProvider myDataProvider */ public function testExample(Result $result) { $this->assertSuccess($result); $this->assertTimeToFirstByte(new TimeToFirstByte(100), $result); $this->assertBodyNotEmpty($result); $this->assertHeaderExists(Header::fromPrimitives(‘App-Server', ‘Fury’), $result); }

public function myDataProvider() { $urls = ['http://www.kartenmacherei.de', …]; $options = new SmokeTestOptions( UrlCollection::fromStrings($urls), new RequestTimeout(2), new FollowRedirects(true), new Concurrency(3), new BodyLength(500) );

return $this->runSmokeTests($options); }

class SmokeTest extends PHPUnit_Framework_TestCase { use SmokeTestTrait;

/** * @dataProvider myDataProvider */ public function testExample(Result $result) { $this->assertSuccess($result); $this->assertTimeToFirstByte(new TimeToFirstByte(100), $result); $this->assertBodyNotEmpty($result); $this->assertHeaderExists(Header::fromPrimitives(‘App-Server', ‘Fury’), $result); }

public function myDataProvider() { $urls = ['http://www.kartenmacherei.de', …]; $options = new SmokeTestOptions( UrlCollection::fromStrings($urls), new RequestTimeout(2), new FollowRedirects(true), new Concurrency(3), new BodyLength(500) );

return $this->runSmokeTests($options); }

class SmokeTest extends PHPUnit_Framework_TestCase { use SmokeTestTrait;

/** * @dataProvider myDataProvider */ public function testExample(Result $result) { $this->assertSuccess($result); $this->assertTimeToFirstByte(new TimeToFirstByte(100), $result); $this->assertBodyNotEmpty($result); $this->assertHeaderExists(Header::fromPrimitives(‘App-Server', ‘Fury’), $result); }

public function myDataProvider() { $urls = ['http://www.kartenmacherei.de', …]; $options = new SmokeTestOptions( UrlCollection::fromStrings($urls), new RequestTimeout(2), new FollowRedirects(true), new Concurrency(3), new BodyLength(500) );

return $this->runSmokeTests($options); }

Output

Features to come next

• Improve ErrorResult object

• Introduce assertions for Redirects

• Improve quality of error message

• 2nd version based on PHPUnit 6

Server Architecture

Webserver (Router)

Webserver

FURY Frontend

Server A

K/V StoreSearch

FURY Backend

Webserver

FURY Frontend

Server B

K/V StoreSearch

FURY Backend

Webserver (Router)

Webserver

FURY Frontend

Server A

K/V StoreSearch

FURY Backend

Webserver

FURY Frontend

Server B

K/V StoreSearch

FURY Backend

active = A

Webserver (Router)

Webserver

FURY Frontend

Server A

K/V StoreSearch

FURY Backend

Webserver

FURY Frontend

Server B

K/V StoreSearch

FURY Backend

active = B

Webserver (Router)

Webserver

FURY Frontend

Server A

K/V StoreSearch

FURY Backend

active = B

RDBMS Read Slave

Webserver

FURY Frontend

Server A

K/V StoreSearch

FURY Backend

Webserver (Router)

Build Server

Deploy Code

active = B

RDBMS Read Slave

Webserver

FURY Frontend

Server A

K/V StoreSearch

FURY Backend

Webserver (Router)

Build Server

Deploy Code

Collect & Export

active = B

Webserver

FURY Frontend

Server A

K/V StoreSearch

FURY Backend

Webserver (Router)

Build Server

Deploy Code

Collect & Export

Smoke Tests

active = B

RDBMS Read Slave

Webserver

FURY Frontend

Server A

K/V StoreSearch

FURY Backend

Webserver (Router)

Build Server

Deploy Code

Collect & Export

Smoke Tests

active = B

RDBMS Read Slave

Webserver

FURY Frontend

Server A

K/V StoreSearch

FURY Backend

Webserver (Router)

Build Server

Deploy Code

Collect & Export

Smoke Tests

active = B

RDBMS Read Slave

Webserver

FURY Frontend

Server A

K/V StoreSearch

FURY Backend

Webserver (Router)

Build Server

Deploy Code

Collect & Export

Smoke Tests

Switch to A

active = Bactive = A

RDBMS Read Slave

Conclusion

• Write tests

• Get 100% coverage

• SmokeTest your Website

• Only activate server if it didn’t start smoking

https://www.facebook.com/kartenmacherei/

[email protected]

http://inside.kartenmacherei.de/job.html

https://tech.kartenmacherei.de

@techdotkam

Contact & Feedback

Q&A