Perl replace

http://topic.csdn.net/u/20090704/21/93f2b26f-28e8-4fc0-b399-f2790dc58572.html
求教Perl中的一个替换问题
假设变量$var = “abcFrank bbbFrank678Frankiii Frank 87tyt”;
现在我想把倒数第一个Frank替换成Perl,如何用一个 $var =~ s///; 语句搞定?
如果是倒数第二个呢?或者有什么其他方法?
多谢了!
$var =~ s/(.*)(Frank)((.*Frank){0})/$1perl$3/; #替换倒数第一个
$var =~ s/(.*)(Frank)((.*Frank){1})/$1perl$3/; #替换倒数第二个
$var =~ s/(.*)(Frank)((.*Frank){2})/$1perl$3/; #替换倒数第三个

Advertisements
发表在 未分类 | 留下评论

A successful Git branching model

A successful Git branching model

Published: January 05, 2010

In this post I present the development model that I’ve introduced for all of my projects (both at work and private) about a year ago, and which has turned out to be very successful. I’ve been meaning to write about it for a while now, but I’ve never really found the time to do so thoroughly, until now. I won’t talk about any of the projects’ details, merely about the branching strategy and release management.

It focuses around Git as the tool for the versioning of all of our source code.

Why git?

For a thorough discussion on the pros and cons of Git compared to centralized source code control systems, see the web. There are plenty of flame wars going on there. As a developer, I prefer Git above all other tools around today. Git really changed the way developers think of merging and branching. From the classic CVS/Subversion world I came from, merging/branching has always been considered a bit scary (“beware of merge conflicts, they bite you!”) and something you only do every once in a while.

But with Git, these actions are extremely cheap and simple, and they are considered one of the core parts of your daily workflow, really. For example, in CVS/Subversion books, branching and merging is first discussed in the later chapters (for advanced users), while in every Git book, it’s already covered in chapter 3 (basics).

As a consequence of its simplicity and repetitive nature, branching and merging are no longer something to be afraid of. Version control tools are supposed to assist in branching/merging more than anything else.

Enough about the tools, let’s head onto the development model. The model that I’m going to present here is essentially no more than a set of procedures that every team member has to follow in order to come to a managed software development process.

Decentralized but centralized

The repository setup that we use and that works well with this branching model, is that with a central “truth” repo. Note that this repo is only considered to be the central one (since Git is a DVCS, there is no such thing as a central repo at a technical level). We will refer to this repo as origin, since this name is familiar to all Git users.

Each developer pulls and pushes to origin. But besides the centralized push-pull relationships, each developer may also pull changes from other peers to form sub teams. For example, this might be useful to work together with two or more developers on a big new feature, before pushing the work in progress to origin prematurely. In the figure above, there are subteams of Alice and Bob, Alice and David, and Clair and David.

Technically, this means nothing more than that Alice has defined a Git remote, namedbob, pointing to Bob’s repository, and vice versa.

The main branches

At the core, the development model is greatly inspired by existing models out there. The central repo holds two main branches with an infinite lifetime:

  • master
  • develop

The master branch at origin should be familiar to every Git user. Parallel to the master branch, another branch exists called develop.

We consider origin/master to be the main branch where the source code of HEAD always reflects aproduction-ready state.

We consider origin/develop to be the main branch where the source code of HEAD always reflects a state with the latest delivered development changes for the next release. Some would call this the “integration branch”. This is where any automatic nightly builds are built from.

When the source code in the develop branch reaches a stable point and is ready to be released, all of the changes should be merged back into master somehow and then tagged with a release number. How this is done in detail will be discussed further on.

Therefore, each time when changes are merged back into master, this is a new production release by definition. We tend to be very strict at this, so that theoretically, we could use a Git hook script to automatically build and roll-out our software to our production servers everytime there was a commit on master.

Supporting branches

Next to the main branches master and develop, our development model uses a variety of supporting branches to aid parallel development between team members, ease tracking of features, prepare for production releases and to assist in quickly fixing live production problems. Unlike the main branches, these branches always have a limited life time, since they will be removed eventually.

The different types of branches we may use are:

  • Feature branches
  • Release branches
  • Hotfix branches

Each of these branches have a specific purpose and are bound to strict rules as to which branches may be their originating branch and which branches must be their merge targets. We will walk through them in a minute.

By no means are these branches “special” from a technical perspective. The branch types are categorized by how we use them. They are of course plain old Git branches.

Feature branches

May branch off from: develop
Must merge back into: develop
Branch naming convention: anything except masterdevelop,release-*, or hotfix-*

Feature branches (or sometimes called topic branches) are used to develop new features for the upcoming or a distant future release. When starting development of a feature, the target release in which this feature will be incorporated may well be unknown at that point. The essence of a feature branch is that it exists as long as the feature is in development, but will eventually be merged back into develop(to definitely add the new feature to the upcoming release) or discarded (in case of a disappointing experiment).

Feature branches typically exist in developer repos only, not inorigin.

Creating a feature branch

When starting work on a new feature, branch off from the develop branch.

$ git checkout -b myfeature develop Switched to a new branch "myfeature"

Incorporating a finished feature on develop

Finished features may be merged into the develop branch definitely add them to the upcoming release:

$ git checkout develop Switched to branch 'develop' $ git merge --no-ff myfeature Updating ea1b82a..05e9557 (Summary of changes) $ git branch -d myfeature Deleted branch myfeature (was 05e9557). $ git push origin develop

The --no-ff flag causes the merge to always create a new commit object, even if the merge could be performed with a fast-forward. This avoids losing information about the historical existence of a feature branch and groups together all commits that together added the feature. Compare:

In the latter case, it is impossible to see from the Git history which of the commit objects together have implemented a feature—you would have to manually read all the log messages. Reverting a whole feature (i.e. a group of commits), is a true headache in the latter situation, whereas it is easily done if the --no-ff flag was used.

Yes, it will create a few more (empty) commit objects, but the gain is much bigger that that cost.

Unfortunately, I have not found a way to make --no-ff the default behaviour of git mergeyet, but it really should be.

Release branches

May branch off from: develop
Must merge back into: develop and master
Branch naming convention: release-*

Release branches support preparation of a new production release. They allow for last-minute dotting of i’s and crossing t’s. Furthermore, they allow for minor bug fixes and preparing meta-data for a release (version number, build dates, etc.). By doing all of this work on a release branch, the develop branch is cleared to receive features for the next big release.

The key moment to branch off a new release branch from develop is when develop (almost) reflects the desired state of the new release. At least all features that are targeted for the release-to-be-built must be merged in to develop at this point in time. All features targeted at future releases may not—they must wait until after the release branch is branched off.

It is exactly at the start of a release branch that the upcoming release gets assigned a version number—not any earlier. Up until that moment, the develop branch reflected changes for the “next release”, but it is unclear whether that “next release” will eventually become 0.3 or 1.0, until the release branch is started. That decision is made on the start of the release branch and is carried out by the project’s rules on version number bumping.

Creating a release branch

Release branches are created from the develop branch. For example, say version 1.1.5 is the current production release and we have a big release coming up. The state of develop is ready for the “next release” and we have decided that this will become version 1.2 (rather than 1.1.6 or 2.0). So we branch off and give the release branch a name reflecting the new version number:

$ git checkout -b release-1.2 develop Switched to a new branch "release-1.2" $ ./bump-version.sh 1.2 Files modified successfully, version bumped to 1.2. $ git commit -a -m "Bumped version number to 1.2" [release-1.2 74d9424] Bumped version number to 1.2 1 files changed, 1 insertions(+), 1 deletions(-)

After creating a new branch and switching to it, we bump the version number. Here, bump-version.sh is a fictional shell script that changes some files in the working copy to reflect the new version. (This can of course be a manual change—the point being that some files change.) Then, the bumped version number is committed.

This new branch may exist there for a while, until the release may be rolled out definitely. During that time, bug fixes may be applied in this branch (rather than on the developbranch). Adding large new features here is strictly prohibited. They must be merged intodevelop, and therefore, wait for the next big release.

Finishing a release branch

When the state of the release branch is ready to become a real release, some actions need to be carried out. First, the release branch is merged into master (since every commit onmaster is a new release by definition, remember). Next, that commit on master must be tagged for easy future reference to this historical version. Finally, the changes made on the release branch need to be merged back into develop, so that future releases also contain these bug fixes.

The first two steps in Git:

$ git checkout master Switched to branch 'master' $ git merge --no-ff release-1.2 Merge made by recursive. (Summary of changes) $ git tag -a 1.2

The release is now done, and tagged for future reference.
Edit: You might as well want to use the -s or -u <key> flags to sign your tag cryptographically.

To keep the changes made in the release branch, we need to merge those back intodevelop, though. In Git:

$ git checkout develop Switched to branch 'develop' $ git merge --no-ff release-1.2 Merge made by recursive. (Summary of changes)

This step may well lead to a merge conflict (probably even, since we have changed the version number). If so, fix it and commit.

Now we are really done and the release branch may be removed, since we don’t need it anymore:

$ git branch -d release-1.2 Deleted branch release-1.2 (was ff452fe).

Hotfix branches

May branch off from: master
Must merge back into: develop and master
Branch naming convention: hotfix-*

Hotfix branches are very much like release branches in that they are also meant to prepare for a new production release, albeit unplanned. They arise from the necessity to act immediately upon an undesired state of a live production version. When a critical bug in a production version must be resolved immediately, a hotfix branch may be branched off from the corresponding tag on the master branch that marks the production version.

The essence is that work of team members (on the develop branch) can continue, while another person is preparing a quick production fix.

Creating the hotfix branch

Hotfix branches are created from the master branch. For example, say version 1.2 is the current production release running live and causing troubles due to a severe bug. But changes on develop are yet unstable. We may then branch off a hotfix branch and start fixing the problem:

$ git checkout -b hotfix-1.2.1 master Switched to a new branch "hotfix-1.2.1" $ ./bump-version.sh 1.2.1 Files modified successfully, version bumped to 1.2.1. $ git commit -a -m "Bumped version number to 1.2.1" [hotfix-1.2.1 41e61bb] Bumped version number to 1.2.1 1 files changed, 1 insertions(+), 1 deletions(-)

Don’t forget to bump the version number after branching off!

Then, fix the bug and commit the fix in one or more separate commits.

$ git commit -m "Fixed severe production problem" [hotfix-1.2.1 abbe5d6] Fixed severe production problem 5 files changed, 32 insertions(+), 17 deletions(-)

Finishing a hotfix branch

When finished, the bugfix needs to be merged back into master, but also needs to be merged back into develop, in order to safeguard that the bugfix is included in the next release as well. This is completely similar to how release branches are finished.

First, update master and tag the release.

$ git checkout master Switched to branch 'master' $ git merge --no-ff hotfix-1.2.1 Merge made by recursive. (Summary of changes) $ git tag -a 1.2.1

Edit: You might as well want to use the -s or -u <key> flags to sign your tag cryptographically.

Next, include the bugfix in develop, too:

$ git checkout develop Switched to branch 'develop' $ git merge --no-ff hotfix-1.2.1 Merge made by recursive. (Summary of changes)

The one exception to the rule here is that, when a release branch currently exists, the hotfix changes need to be merged into that release branch, instead ofdevelop. Back-merging the bugfix into the release branch will eventually result in the bugfix being merged into develop too, when the release branch is finished. (If work indevelop immediately requires this bugfix and cannot wait for the release branch to be finished, you may safely merge the bugfix into develop now already as well.)

Finally, remove the temporary branch:

$ git branch -d hotfix-1.2.1 Deleted branch hotfix-1.2.1 (was abbe5d6).

Summary

While there is nothing really shocking new to this branching model, the “big picture” figure that this post began with has turned out to be tremendously useful in our projects. It forms an elegant mental model that is easy to comprehend and allows team members to develop a shared understanding of the branching and releasing processes.

A high-quality PDF version of the figure is provided here. Go ahead and hang it on the wall for quick reference at any time.

Update: And for anyone who requested it: here’s the gitflow-model.src.key of the main diagram image (Apple Keynote).

发表在 未分类 | 留下评论

getting past untrusted HTTPS connections with selenium

getting past untrusted HTTPS connections with selenium

http://fijiaaron.wordpress.com/2010/03/16/getting-past-untrusted-connections-on-self-signed-ssl-certs-using-selenium/

A common problem many Selenium users run into is the untrusted connection warning.

This happens when an SSL certificate is unsigned, self-signed, or doesn’t match the domain name, a common scenario in test environments. In Firefox it used to be a popup modal dialog that needed dismissed by clicking “ok” or “so what” or something along those lines. More recent versions of Firefox (I have 3.5.8) bring up an intermediate page that says “This Connection is Untrusted” and looks like this:

What should you do?

  1. Click “I Understand the Risks”
  2. Click “Add Exception”
  3. Click “Get Certificate”
  4. Make sure “Permanently store this exception” is checked (it is by default)
  5. Click “Confirm Security Exception”

There, now don’t you feel safer for all that clicking.

Earlier releases of Firefox 3.5  had a bug that it wouldn’t “permanently” store the SSL Certificate, and there was even a plugin created to fix that.

Well, that’s all fine a dandy, but unless you want to click through that manually every time you run tests in Selenium, you’ve got a problem.  See, it’s not an actual page, which means there’s no DOM for javascript to access,  so you can’t use selenium to click through it.  And selenium starts fresh with a new profile every time.

But that’s only by default.  You can tell Selenium to use an existing profile as a template by passing the -firefoxProfileTempate flag like this:

java -jar selenium-server.jar -firefoxProfileTemplate  "c:\Documents and Settings\Aaron Evans\Application Data\Mozilla\Firefox\Profiles\5rdxety0.default"

If you’ve already dismissed the dire warnings manually with your existing profile, now Selenium will sail right through.  But only if you use Firefox.  I’ll tell you how to get past this problem with IE, Opera, Chrome, and Safari another day.

But first, let’s create a custom profile that doesn’t have all the junk you’ve loaded into Firefox (like vimperator and firebug) to make it run a bit quicker and cleaner.

  1. Close all your firefox windows down (don’t forget the quick launch if you have that)
  2. Launch firefox from the command line with
    firefox.exe -ProfileManager -no-remote
  3. Click “Create Profile”
  4. Click “Next” on the Create Profile Wizard” nonsense popup
  5. Create a name for your new profile — I think “Selenium” is pretty descriptive
  6. Click “Choose Folder”
  7. Pick something easy to find — like “C:\selenium\firefox_profile”
  8. Click Finish

Now click through and accept all the SSL certificates on the site you need to run Selenium tests on, repeating the process described above.

Finally, launch selenium-server and specify the profile you just created:

java -jar selenium-server.jar -firefoxProfileTemplate c:\selenium\firefox_profile

You can do a bunch of other cool stuff with your firefox profile for selenium, but we’ll talk about that later.  I’m eager to hear what others have done as well.

One thing I’d like to figure out is how to get rid of that update manager popup that shows up every time I run tests (but doesn’t interfere with them.)

发表在 未分类 | 标签为 | 留下评论

Selenium

http://www.slideshare.net/davehunt82/selenium-2-user-interactions-api

http://release.seleniumhq.org/selenium-remote-control/0.9.2/doc/java/com/thoughtworks/selenium/Selenium.html

Fill in the file name.

driver.findElement(By.id(“upload”)).sendKeys(testFile.getAbsolutePath());

Add profile dir

http://seleniumhq.org/docs/03_webdriver.html

Alternatively, if the profile isn’t already registered with Firefox:

File profileDir = new File("path/to/top/level/of/profile");
FirefoxProfile profile = new FirefoxProfile(profileDir);
profile.addAdditionalPreferences(extraPrefs);
WebDriver driver = new FirefoxDriver(profile);
Enabling features that might not be wise to use in Firefox

Selenium Tutorial : Selenium2

http://marakana.com/bookshelf/selenium_tutorial/selenium2.html

12. Selenium 2.0

  • The next major version of Selenium is going to change a lot of things on the Selenium internals
  • Selenium 2.0 will be in fact be a merge between the Selenium and WebDriver projects
  • Currently, Selenium 2.0 is still in development: last version at the time of writing is alpha 6

12.1. Differences & New Features

  • Selenium 2.0 intends to get rid of Selenium RC
    • The driver will directly drive the browser using WebDriver
    • Parallelization is easier: the test code takes care of it
  • Selenium 2.0 comes as a browser extension directly plugging into the browser automation features, allowing to:
    • Avoid the JavaScript security model (same origin policy rule) that restricts Selenium 1.x capabilities
      • It will be possible to test features on several domains (like Facebook connect for instance)
  • Selenium 2.0 works at the OS/browser level:
    • For instance, command type works at the OS level rather than changing the value of the input elements with JavaScript
    • It drives the browser much more effectively: forget the limitations of Selenium 1.x like the file upload or download, pop-ups and dialogs barrier or self-signed certificates problems
  • In addition, WebDriver provides a real object-based API giving you the ability to leverage the PageObject pattern very easily
  • The merge of the projects combines the strenghts of both frameworks: Selenium 2.0 will provide both Selenium 1.x and WebDriver APIs and it will be possible to use these APIs with both Selenium and WebDriver backends

12.2. API

[Note] Note
The following examples are Java-based as the API is not available in Ruby yet. At the time of writing, only Java, C# and Python APIs are available

12.2.1. The WebDriver object

  • Currently, WebDriver provides 4 implementations of its driver:
    • HtmlUnitDriver, a pure Java driver based on HtmlUnit browser simulator (all Java-capable OS)
      • When running, you won’t see any window opening because it doesn’t render any page like Firefox would. You can’t use it to get size or position of pages’ elements
      • It is very fast but does not provides JavaScript yet: this feature is still a WIP. If you want to use it anyway, use driver.setJavascriptEnabled(true).
    • FirefoxDriver: supports Firefox (2.x and 3.x, all OS)
    • InternetExplorerDriver: supports InternetExplorer (tested on IE6, 7 and 8, should work on IE5.5 and on Windows XP and Vista)
    • ChromeDriver: drives Google’s browser (>= 4.0, all OS)
  • Here is an example of a test using HtmlUnitDriver:
    package org.openqa.selenium.example;
    
    import org.openqa.selenium.By;
    import org.openqa.selenium.WebDriver;
    import org.openqa.selenium.WebElement;
    import org.openqa.selenium.htmlunit.HtmlUnitDriver;
    
    public class Example  {
        public static void main(String[] args) {
            WebDriver driver = new HtmlUnitDriver(); //

    1

            // And now use this to visit Google
            driver.get("http://www.google.com"); //

    2

            // Find the text input element by its name
            WebElement element = driver.findElement(By.name("q")); //

    3

            // Enter something to search for
            element.sendKeys("Cheese!"); //

    4

            // Now submit the form. WebDriver will find the form for us from the element
            element.submit(); //

    5

            // Check the title of the page
            System.out.println("Page title is: " + driver.getTitle());
        }
    }
    1 We create a new WebDriver object using HtmlUnit as a browser.
    2 get is the equivalent of open
    3 Each element of the page is an instance of WebElement
    4 WebElement provides the methods to interact with the element. If you call an invalid method on an element (toggle() on a Button for instance), an exception will be thrown
    5 The submit() method will automatically find the form enclosing the element and submit it. If none is present, it will throw a NoSuchElementException
  • You can also interact with the frames and windows of the browser:
    for (String handle : driver.getWindowHandles()) { //

    1

      driver.switchTo().window(handle);
    }
    
    ...
    
    driver.switchTo().frame("frameName");
    driver.switchTo().frame("frameName.0.child"); //

    2

    1 You can get the list of the windows opened in the browser withgetWindowHandles(). If you know the handle of the window (target attribute of an anchor element) you can just call driver.switchTo().window("window handle")
    2 You can also acces the subframes of a frame using the dot and both name and index
  • The driver object also provides navigation methods:
    driver.navigate().to("http://www.example.com"); //

    1

    driver.navigate().forward();
    driver.navigate().back();
    1 driver.get("url"); is just an alias to driver.navigate().to("url")
  • You can also manage cookies via the Options interface that is accessible throughmanage()
    // Go to the correct domain
    driver.get("http://www.example.com");
    
    // Now set the cookie. This one's valid for the entire domain
    Cookie cookie = new Cookie("key", "value");
    driver.manage().addCookie(cookie);
    
    // And now output all the available cookies for the current URL
    Set<Cookie> allCookies = driver.manage().getCookies();
    for (Cookie loadedCookie : allCookies) {
        System.out.println(String.format("%s -> %s", loadedCookie.getName(), loadedCookie.getValue()));
    }

12.2.2. WebElement objects

  • WebElement provides methods to do simple interactions with your HTML elements: type, click, select…
  • RenderedWebElements represents a HTML element as if it was rendered in the browser and so provides access to size, location, access to css properties or drag&drop:
    WebElement plain = driver.findElement(By.name("q"));
    RenderedWebElement element = (RenderedWebElement) plain;
    
    ...
    
    RenderedWebElement element = (RenderedWebElement) driver.findElement(By.name("source"));
    RenderedWebElement target = (RenderedWebElement) driver.findElement(By.name("target"));
    
    element.dragAndDropOn(target);

12.2.3. PageFactory

  • WebDriver provides native support for the PageObject patern through the PageFactoryobject
  • Consider the following PageObject:
    package org.openqa.selenium.example;
    
    import org.openqa.selenium.WebElement;
    
    public class GoogleSearchPage {
        private WebElement q; //

    1

        public void searchFor(String text) {
            q.sendKeys(text); //

    2

            q.submit();
        }
    }
    1 Here we declare our WebElement
    2 We use it but notice that we never instanciated it
  • Now, we use the GoogleSearchPage class in our test class:
    package org.openqa.selenium.example;
    
    import org.openqa.selenium.WebDriver;
    import org.openqa.selenium.WebElement;
    import org.openqa.selenium.htmlunit.HtmlUnitDriver;
    import org.openqa.selenium.support.PageFactory;
    
    public class UsingGoogleSearchPage {
        public static void main(String[] args) {
            WebDriver driver = new HtmlUnitDriver();
    
            driver.get("http://www.google.com/");
    
            GoogleSearchPage page = PageFactory.initElements(driver, GoogleSearchPage.class); //

    1

            page.searchFor("Cheese");
        }
    }
    1 initElements will instanciate the WebElements properties of the page for us – but we never specified what element q was mapped to?!
  • The PageFactory will use the name of the properties to find our elements on the pages: Here our search field is named q and PageFactory will map it to the page element with the same id, that is the search input field:q.sendKeys(text); is the same as driver.findElement(By.id("q")).sendKeys(text);
  • In order for PageFactory to work properly, your PageObjects should have a constructor with only one argument: the driver instance:
    public class GoogleSearchPage {
    
        public GoogleSearchPage(WebDriver driver) { }
    }
  • You can change the behavior of the PageFactory’s locator lookup using annotations:
    public class GoogleSearchPage {
    
        @FindBy(how = How.NAME, using = "q")
        private WebElement searchBox;
    
        ....
    }

    Here we’ll use the name attribute to locate our elements

  • The default behavior of WebDriver is to lookup for the element each time it is accessed. In an Ajax-enabled application, this is ok since some elements may disappear but on a static page, it is useless.You can use the @CacheLookup annotation to cache the element mapping:
        @FindBy(how = How.NAME, using = "q")
        @CacheLookup
        private WebElement searchBox;

Selenium 2 Examples

http://seleniumexamples.com/blog/examples/selenium-2-examples/

Posted: December 11th, 2009 | Author: Dave | Filed under: Examples | Tags: , | 6 Comments »

Yesterday Selenium 2 (alpha 1) was released. This is the first release since the Selenium and WebDriver projects started to merge. The main difference is the inclusion of the WebDriver API into Selenium. I’ve put together a small example below that uses the new API to log into two web based e-mail clients and send an e-mail.

WebDriverTestBase.java

package tests;

import org.openqa.selenium.WebDriver;
import org.openqa.selenium.firefox.FirefoxDriver;
import org.openqa.selenium.support.ui.Wait;
import org.openqa.selenium.support.ui.WebDriverWait;
import org.testng.Assert;
import org.testng.annotations.AfterClass;
import org.testng.annotations.BeforeClass;

public class WebDriverTestBase {

	public static FirefoxDriver driver;
	public static Wait wait;

	@BeforeClass(alwaysRun = true)
    protected void startWebDriver() {
    	driver = new FirefoxDriver();
    	wait = new WebDriverWait(driver, 120);
    }

    @AfterClass(alwaysRun = true)
    protected void closeSession() {
	    driver.close();
    }

    public static void assertEquals(Object actual, Object expected) {
    	Assert.assertEquals(actual, expected);
    }

}

VisibilityOfElementLocated.java

package tests;

import org.openqa.selenium.By;
import org.openqa.selenium.WebDriver;
import org.openqa.selenium.support.ui.ExpectedCondition;

public class VisibilityOfElementLocated implements ExpectedCondition {

	By findCondition;

	VisibilityOfElementLocated(By by) {
		this.findCondition = by;
	}

	public Boolean apply(WebDriver driver) {
		driver.findElement(this.findCondition);
		return Boolean.valueOf(true);
	}

}

WebmailTest.java

package tests;

import org.openqa.selenium.By;
import org.testng.annotations.Test;

public class WebmailTest extends WebDriverTestBase {

	//variables
	public static final String YAHOO_EMAIL = "example@yahoo.co.uk";
	public static final String HOTMAIL_EMAIL = "example@hotmail.co.uk";

	@Test(description = "Sends an e-mail from Yahoo account")
	public void sendFromYahoo() {
		//new message variables
		String to = HOTMAIL_EMAIL;
		String subject = "Test Sending Email Message From Yahoo";
		String message = "This is a test e-mail from Yahoo";

		//login to yahoo
		driver.get("http://mail.yahoo.com/");
		driver.findElement(By.id("username")).sendKeys(YAHOO_EMAIL);
		driver.findElement(By.id("passwd")).sendKeys("mytestpw");
		driver.findElement(By.id(".save")).click();

		//create new message
		driver.findElement(By.id("compose_button_label")).click();
		wait.until(new VisibilityOfElementLocated(By.xpath("id('_testTo_label')/ancestor::tr[1]//textarea")));

		//send test message
		driver.findElement(By.xpath("id('_testTo_label')/ancestor::tr[1]//textarea")).sendKeys(to);
		driver.findElement(By.xpath("id('_testSubject_label')/ancestor::tr[1]//input")).sendKeys(subject);
		driver.switchTo().frame("compArea_test_");
		driver.findElement(By.xpath("//div")).sendKeys(message);
		driver.switchTo().defaultContent();
		driver.findElement(By.id("SendMessageButton_label")).click();
		//WARNING! sometimes a captcha is displayed here
		wait.until(new VisibilityOfElementLocated(By.xpath("//nobr[contains(text(), 'Message Sent')]")));
	}

	@Test(description = "Sends an e-mail from Hotmail account")
	public void sendFromHotmail() {
		//new message variables
		String to = YAHOO_EMAIL;
		String subject = "Test Sending Email Message From Hotmail";
		String message = "This is a test e-mail from Hotmail";

		//login to hotmail
		driver.get("http://mail.live.com/");
		driver.findElement(By.name("login")).sendKeys(HOTMAIL_EMAIL);
		driver.findElement(By.name("passwd")).sendKeys("mytestpw");
		if (driver.findElement(By.name("remMe")).isSelected()) {
			driver.findElement(By.name("remMe")).click();
		}
		driver.findElement(By.name("SI")).click();

		//create new message
		driver.switchTo().frame("UIFrame");
		driver.findElement(By.id("NewMessage")).click();

		//send test message
		driver.findElement(By.id("AutoCompleteTo$InputBox")).sendKeys(to);
		driver.findElement(By.id("fSubject")).sendKeys(subject);
		driver.switchTo().frame("UIFrame.1");
		driver.findElement(By.xpath("//body")).sendKeys(message);
		driver.switchTo().frame("UIFrame");
		driver.findElement(By.id("SendMessage")).click();
		assertEquals(driver.findElement(By.cssSelector("h1.SmcHeaderColor")).getText(), "Your message has been sent");
	}

}

Disclaimer: These tests are working at the time of this post but do require active e-mail accounts. They are likely to fail when the web based e-mail clients update their applications. Also, please don’t misuse these examples – their intention is to show how to use the WebDriver API and were inspired by a test assignment for an interview process.


6 Comments on “Selenium 2 Examples”

  1. 1Gergely said at 10:13 am on April 26th, 2010:Hi!

    I just gone over the code once more and there is a part i don’t understand..

    public Boolean apply(WebDriver driver) {
    driver.findElement(this.findCondition);
    return Boolean.valueOf(true);
    }

    Doesn’t this always return true? And i don’t see you using it sort of.. Is that part of the interface and must be implemented?

    Thanks,
    Gergely.

  2. 2Dave said at 3:24 pm on April 26th, 2010:It will always return true, unless an exception occurs. The findElement method will throw a NoSuchElementException if the element doesn’t exist. This is no longer required in Selenium 2.0a4 as there is support for implicit waits, however these only wait for the element to be present, which means it’s not necessarily visible (or enabled, etc).

  3. 3Gergely said at 9:20 am on April 27th, 2010:Ahh i understand now! Thanks very much for the explanation!

  4. 4Shanmugavel said at 1:11 pm on October 19th, 2010:Hi all,
    I am trying Webdriver with C# – Visual Studio and i followed instructions…
    Finally i can’t listed WebDriver namespace under selenium as below..

    using org.openqa.selenium.WebDriver;

    Can anybody help me?

    Thx,
    SCSVEL

  5. 5JoseDev said at 6:21 pm on March 16th, 2011:I’m trying to test the code to learn how it properly works but y get a compilation error in VisibilityOfElementLocated class since its suposed to implement the apply func as public Object aply(Object t). how can I fix this? Cheers

  6. 6Dave said at 1:38 pm on March 17th, 2011:The VisibilityOfElementLocated is no longer needed as the latest version on Selenium 2 (currently 2.0b2) supports implicit waits. With implicit waits, you only need to use one of the findElement methods, and if the target element does not exist or is not visible, Selenium will wait until it is. Unfortunately this example is out of date, however if you look at some of my more recent examples, hopefully you will find them to be working.

A simple Selenium 2 example March 1, 2011

http://www.qaautomation.net/?p=263

Introduction

As mentioned in the Introduction to Selenium post, Selenium is a great test automation tool for driving browsers for testing web applications. Selenium contributors are now coming out with Selenium 2 which has some new, more expressive APIs, along with backward compatibility. This post describes:

  • Downloading and setting up Selenium 2
  • Running a simple test written using Selenium 2′s new API in Java.

The assumption here is that you have an environment setup similar to the one defined in the Creating your Java project workspace post.

Downloading and setting up Selenium 2

At this time, Selenium 2 is at beta 2. Follow these steps to add Selenium in your project.

  1. Download Selenium 2.0b2 zip file in your download directory … on unix lets assume its located at ~/Downloads
  2. Unzip the file by doing
    unzip selenium-java-2.0b2.zip
  3. You will notice several jar files in the exploded folder. You could copy all the jar files, but for this example, all you need are commons-logging-1.1.1.jar, httpclient-4.0.2.jar, selenium-java-2.0b2.jar, guava-r08.jar, httpcore-4.0.1.jar, hamcrest-all-1.1.jar, json-20080701.jar. Copy these to your project lib (testautomation/lib/.) directory.

Writing your first test in Java

Unlike previous versions of Selenium, starting the selenium server is optional. In this case, we are not going to start the selenium server.

Let us start with creating a class org.qaautomation.examples.GoogleSearch.java

1 package net.qaautomation.examples;
2
3 import org.openqa.selenium.By;
4 import org.openqa.selenium.WebDriver;
5 import org.openqa.selenium.firefox.FirefoxDriver;
6 import org.openqa.selenium.support.ui.ExpectedCondition;
7 import org.openqa.selenium.support.ui.Wait;
8 import org.openqa.selenium.support.ui.WebDriverWait;
9
10 /**
11  * Search Google example.
12  *
13  * @author Rahul
14  */
15 public class GoogleSearch {
16     static WebDriver driver;
17     static Wait<WebDriver> wait;
18
19     public static void main(String[] args) {
20         driver = new FirefoxDriver();
21         wait = new WebDriverWait(driver, 30);
22         driver.get("http://www.google.com/");
23
24         boolean result;
25         try {
26             result = firstPageContainsQAANet();
27         catch(Exception e) {
28             e.printStackTrace();
29             result = false;
30         finally {
31             driver.close();
32         }
33
34         System.out.println("Test " + (result? "passed." "failed."));
35         if (!result) {
36             System.exit(1);
37         }
38     }
39
40     private static boolean firstPageContainsQAANet() {
41         //type search query
42         driver.findElement(By.name("q")).sendKeys("qa automation\n");
43
44         // click search
45         driver.findElement(By.name("btnG")).click();
46
47         // Wait for search to complete
48         wait.until(new ExpectedCondition<Boolean>() {
49             public Boolean apply(WebDriver webDriver) {
50                 System.out.println("Searching ...");
51                 return webDriver.findElement(By.id("resultStats")) != null;
52             }
53         });
54
55         // Look for QAAutomation.net in the results
56         return driver.findElement(By.tagName("body")).getText().contains("qaautomation.net");
57     }
58 }

Do
ant build
and
ant run-example -Dexample=GoogleSearch
to run the example. You will notice a firefox window open, do the search and end with the test passing if qaautomation.net shows up as one of the search results.

Posted by Rahul Poonekar in : Selenium trackback


4 Responses to “A simple Selenium 2 example”

  1. Ramdas Singh says:

    Hi Rahul,

    I work as a software test engineer for SRA International. As a volunteer I teach a course on “Test Automation Using Selenium” for SRA University (a small unit of SRA). During the fall of 2010 I taught the course using Selenium 1. But during the spring of 2011 I have planned to teach the course using Selenium 2. I tested your code and it worked. If you come to Virginia, you can stay with us if you like to.

    Thanks for putting the example on the web.

    Regards,

    Ramdas Singh

  2. I have been playing with Eclipse IDE and java Webdriver for only 3 hours and tried this example which worked a treat. thanks

  3. Naresh says:

    This helped alot to explore….thanks…

  4. David says:

    Very different from Selenium 1. I like the expressive API.

    It would be interesting to see a JUnit example (showing typical use of assertions).

Selenium Remote Control For Java — A Tutorial

http://www.bitmotif.com/selenium/selenium-remote-control-for-java-a-tutorial/

March 18, 2007 by pjberry

The coolest element nowadays is Selenium. You can even control it remotely.

What is Selenium?
Selenium is a testing tool for web applications that uses JavaScript and Iframes to run tests directly in a browser. There are several test tools based on this technology: Selenium CoreSelenium IDESelenium Remote Control, and Selenium on Rails.

The aforementioned Selenium Remote Control has become the tool I reach for when testing web applications. In fact, it is so useful that I hardly use HttpUnit any more.

What is Selenium Remote Control?
It is the remote control for Selenium. Duh. Ok, it really is that. A better, less obnoxious description is that Selenium Remote Control is a tool that allows us to test against the browser using our programming language of choice (in this case, Java).

How does Selenium Remote Control Work?
Selenium Remote Control depends on a server called—what else?—Selenium Server. The Selenium Server is capable of manipulating supported browsers and acts as a client-configured proxy between a browser and a website. This allows it to run JavaScript against a site.

How do I use Selenium Remote Control?
First, we’ll need to get the jars. With the jars, we’ll get the server and the client we’ll use for testing. (For this tutorial, the selenium-remote-control-0.9.1-SNAPSHOT nightly was used.) In the folder structure of the download, there are two jars that we want: selenium-server.jar in the “server” folder and selenium-java-client-driver.jar in the “java” folder.

We need to be able to start and stop the Selenium Server. We can do this at the command line:

Start:

java -jar selenium-server.jar

Stop:

http://localhost:4444/selenium-server/driver/?cmd=shutDown

To limit configuration and external dependencies, we can do this in our test code using the SeleniumServer class:

SeleniumServer server = new SeleniumServer();
server.start();
...
server.stop();

With the server running, we may now use a client:

Selenium selenium = new DefaultSelenium( String seleniumServerHost,
                                         int seleniumServerPort,
                                         String browserType,
                                         String baseURL);
selenium.open("http://www.somesite.com/somePage.html");
selenium.stop();

An explanation of the variables in the DefaultSelenium constructor:

  • seleniumServerHost is the where the Selenium Server is running. Typically, it is localhost.
  • seleniumServerPort is the port on which the Selenium Server is listening. The default is 4444.
  • browserType is the type of browser you want to use for testing. Common browser types are *firefox, *iexplore, *opera.
  • baseURL is the base URL for the site you are testing. To adhere to the Same Origin Policy , the Selenium object created is tied to that particular URL and can only be used for that URL.

Now, just opening a page isn’t all that useful. We need to interact with the page. To do this, we use our selenium client’s methods with locators. For example:

selnium.click("link=Text For Some Link");

The string “link=Text For Some Link” is a locator. Most of operations involve locators that tie a Selenium command to elements in an HTML document.

Locators take the form of

“locatorType=argument”

A locator type can be an element id, an element name, an xpath expression, link text, and more.

A few examples:

selenium.click(“id=idOfThing”);                           //an id locator
selenium.click(“name=nameOfThing”);                       //a name locator
selenium.click(“xpath=//img[@alt='The image alt text']”); //an xpath locator
selenium.click(“dom=document.images[56]” );               //a DOM locator
selenium.click(“link=Test Page For Selenium”);            //a link locator
selenium.click(“css=span#firstChild”);                    //a css locator

Of course, there is more to Selenium than just clicking. But, the above gives you an idea of the types of locators, and how they are typically used with a method on the selenium object. We’ll explore other actions (methods) and locator types later.

The last step is to integrate the interaction and checking in a test. In this case, we’ll use JUnit to check the results of clicking a link. Note that the code below actually refers to a real link and page.

package com.bitmotif.seleniumexamples;

import com.thoughtworks.selenium.Selenium;
import com.thoughtworks.selenium.DefaultSelenium;
import junit.framework.TestCase;
import org.openqa.selenium.server.SeleniumServer;

public class ExampleTest
   extends TestCase
{
   private static final String MAX_WAIT_TIME_IN_MS = "60000";
   private static final String BASE_URL = "http://www.bitmotif.com";
   private Selenium selenium = new DefaultSelenium( "localhost",
                                                    4444,
                                                    "*firefox",
                                                    BASE_URL);
   private SeleniumServer seleniumServer;
   public void setUp()
      throws Exception
   {
      seleniumServer = new SeleniumServer();
      seleniumServer.start();
      selenium.start();
   }

   public void tearDown()
      throws Exception
   {
      selenium.stop();
      seleniumServer.stop();
   }

   public void testClickingLink()
      throws Exception
   {
      selenium.open(BASE_URL);
      selenium.click("link=Test Page For Selenium Remote Control");
      selenium.waitForPageToLoad(MAX_WAIT_TIME_IN_MS);

      String expectedTitle = "Bit Motif » Test Page For Selenium Remote Control";
      assertEquals(expectedTitle, selenium.getTitle());
   }
}

The only thing new in the code above is the waitForPageToLoad method. Sometimes an action such as clicking a link or submitting a form results in a page load. In order to make sure the new page is loaded before we attempt to do anything else, we use this method.

With that, we now have an example of using Selenium Remote Control as part of a test.

发表在 未分类 | 标签为 , | 留下评论

Mozilla’s Build System

http://anamariamoz.wordpress.com/2010/11/08/mozillas-build-system/

Mozilla’s Build System

with 11 comments

Mozilla’s Build System is a very cool distributed system run by Buildbot. The system automatically rebuilds and tests the tree every time something has changed.

The Build Infrastructure currently has around 1,000 machines grouped into 3 pools, each made up of severalBuild Masters and many Slaves:

  • Build Pool (handles builds triggered by all changes, except those going to Try):
    • 4 Build Masters
    • ~300 Slaves
  • Try Build Pool (handles Try builds):
    • 1 Build Master
    • ~200 Slaves
  • Test Pool (handles all tests, including Try)
    • 7 Test Masters
    • ~400 Slaves

How it works

The hg poller looks for new changes in the hg.mozilla.org repository every few minutes. The changes are picked up by the Build Scheduler Master, which creates Build Requests, one for each of the supported platforms. The Build Requests go into the Scheduler Database as pending. The Build Masters look for pending Build Requests and take them on only if there are free Slaves to assign them to.

Mozilla's Build System

As the builds complete, the Build Master updates their statuses in the Scheduler Database. Also, the Test Scheduler Master creates Test Build Requests for the corresponding tests.

Next, the Test Build Requests are picked up by the Test Masters and assigns them to free Slaves. When the tests are complete, the Test Master updates back their statuses in the Scheduler Database.

Each Build Master and Test Master controls its own set of Slaves.

Build Run Life Cycle

One push to mozilla-central, if successful, generates a total of 168 Build Requests (as of October 2010, but subject to change in the future), from which 10 are builds (one for each of the supported 10 platforms), 108 unittests and 50 talos tests. All these build requests make up a Build Run.

Each of the 10 platform builds comes with its own set of test requests. The tests are created only when the corresponding build completes, and only if successful. Which means that if there are failed builds, some of the tests won’t be created, and the Build Run won’t have 168 Build Requests, but less.

Build Run Life Cycle

Two very important measures in a Build Runs’s life cycle are the Wait Time and End to End Time.

The Wait Time measures how long Build Requests wait in the queue before starting, more specific, it measures the time difference between the timestamp of the change that generated that Build Request and the timestamp of when that Build Request is assigned to a free slave. (see Build Run Life Cycle diagram above)

The End to End Time measures how long it takes for a Build Run to complete. That is, the time difference between the timestamp of the change that triggered this Build Run and the timestamp of when the last of the generated Build Requests ends (in other words, when all builds and tests are completed). (see Build Run Life Cycle diagram above)

The normal End to End Time for mozilla-central is a little under 4 hours, but greatly varies upwards with the system load.

The Great Wall of Mac minis

The builds are done on a mix of VMs, 1U servers, xserves and Mac minis, and all the testing is done on Mac minis.

The Great Wall of Mac minis is made up of a little over 400 of the Mac minis’ boxes, and is located by the Release Engineers’ desks in the Mountain View office. :D

发表在 未分类 | 留下评论

UI coding work

http://www.w3.org/
http://api.jquery.com/

发表在 未分类 | 标签为 | 留下评论

How Facebook Ships Code

http://framethink.wordpress.com/2011/01/17/how-facebook-ships-code/

How Facebook Ships Code

Posted: January 17, 2011 | Author: yeeguy | Filed under: business managementproduct managementsocial networks,startups | 257 Comments »

I’m fascinated by the way Facebook operates.  It’s a very unique environment, not easily replicated (nor would their system work for all companies, even if they tried).  These are notes gathered from talking with many friends at Facebook about how the company develops and releases software.

Seems like others are also interested in Facebook…   The company’s developer-driven culture is coming under greater public scrutiny and other companies are grappling with if/how to implement developer-driven culture.   The company is pretty secretive about its internal processes, though.  Facebook’s Engineering team releases public Notes on new features and some internal systems, but these are mostly “what” kinds of articles, not “how”…  So it’s not easy for outsiders to see how Facebook is able to innovate and optimize their service so much more effectively than other companies.  In my own attempt as an outsider to understand more about how Facebook operates, I assembled these observations over a period of months.  Out of respect for the privacy of my sources, I’ve removed all names and mention of specific features/products.  And I’ve also waited for over six months to publish these notes, so they’re surely a bit out-of-date.   I hope that releasing these notes will help shed some light on how Facebook has managed to push decision-making “down” in its organization without descending into chaos…  It’s hard to argue with Facebook’s results or the coherence of Facebook’s product offerings.  I think and hope that many consumer internet companies can learn from Facebook’s example.

HUGE thanks to the many folks who helped put together this view inside of Facebook.   Thanks are also due to folks like epriest and fryfrog who have written up corrections and edits.

Notes:

  • as of June 2010, the company has nearly 2000 employees, up from roughly 1100 employees 10 months ago.  Nearly doubling staff in under a year!
  • the two largest teams are Engineering and Ops, with roughly 400-500 team members each.  Between the two they make up about 50% of the company.
  • product manager to engineer ratio is roughly 1-to-7 or 1-to-10
  • all engineers go through 4 to 6 week “Boot Camp” training where they learn the Facebook system by fixing bugs and listening to lectures given by more senior/tenured engineers.  estimate 10% of each boot camp’s trainee class don’t make it and are counseled out of the organization.
  • after boot camp, all engineers get access to live DB (comes with standard lecture about “with great power comes great responsibility” and a clear list of “fire-able offenses”, e.g., sharing private user data)
  • [EDIT thx fryfrog“There are also very good safe guards in place to prevent anyone at the company from doing the horrible sorts of things you can imagine people have the power to do being on the inside. If you have to “become” someone who is asking for support, this is logged along with a reason and closely reviewed. Straying here is not tolerated, period.”
  • any engineer can modify any part of FB’s code base and check-in at-will
  • very engineering driven culture.  ”product managers are essentially useless here.” is a quote from an engineer.  engineers can modify specs mid-process, re-order work projects, and inject new feature ideas anytime.  [EDITORIAL] The author of this blog post is a product manager, so this sentiment really caught my attention.  As you’ll see in the rest of these notes, though, it’s apparent that Facebook’s culture has really embraced product management practices so it’s not as though the role of product management is somehow ignored or omitted.  Rather, the culture of the company seems to be set so that *everyone* feels responsibility for the product.
  • during monthly cross-team meetings, the engineers are the ones who present progress reports.  product marketing and product management attend these meetings, but if they are particularly outspoken, there is actually feedback to the leadership that “product spoke too much at the last meeting.”  they really want engineers to publicly own products and be the main point of contact for the things they built.
  • resourcing for projects is purely voluntary.
    • a PM lobbies group of engineers, tries to get them excited about their ideas.
    • Engineers decide which ones sound interesting to work on.
    • Engineer talks to their manager, says “I’d like to work on these 5 things this week.”
    • Engineering Manager mostly leaves engineers’ preferences alone, may sometimes ask that certain tasks get done first.
    • Engineers handle entire feature themselves — front end javascript, backend database code, and everything in between.  If they want help from a Designer (there are a limited staff of dedicated designers available), they need to get a Designer interested enough in their project to take it on.  Same for Architect help.  But in general, expectation is that engineers will handle everything they need themselves.
  • arguments about whether or not a feature idea is worth doing or not generally get resolved by just spending a week implementing it and then testing it on a sample of users, e.g., 1% of Nevada users.
  • engineers generally want to work on infrastructure, scalability and “hard problems” — that’s where all the prestige is.  can be hard to get engineers excited about working on front-end projects and user interfaces.  this is the opposite of what you find in some consumer businesses where everyone wants to work on stuff that customers touch so you can point to a particular user experience and say “I built that.”  At facebook, the back-end stuff like news feed algorithms, ad-targeting algorithms, memcache optimizations, etc. are the juicy projects that engineers want.
  • commits that affect certain high-priority features (e.g., news feed) get code reviewed before merge. News Feed is important enough that Zuckerberg reviews any changes to it, but that’s an exceptional case.
  • [CORRECTION — thx epriest“There is mandatory code review for all changes (i.e., by one or more engineers). I think the article is just saying that Zuck doesn’t look at every change personally.”
  • [CORRECTION thx fryfrog“All changes are reviewed by at least one person, and the system is easy for anyone else to look at and review your code even if you don’t invite them to. It would take intentionally malicious behavior to get un-reviewed code in.”
  • no QA at all, zero.  engineers responsible for testing, bug fixes, and post-launch maintenance of their own work.  there are some unit-testing and integration-testing frameworks available, but only sporadically used.
  • [CORRECTION thx fryfrog“I would also add that we do have QA, just not an official QA group. Every employee at an office or connected via VPN is using a version of the site that includes all the changes that are next in line to go out. This version is updated frequently and is usually 1-12 hours ahead of what the world sees. All employees are strongly encouraged to report any bugs they see and these are very quickly actioned upon.”
  • re: surprise at lack of QA or automated unit tests — “most engineers are capable of writing bug-free code.  it’s just that they don’t have an incentive to do so at most companies.  when there’s a QA department, it’s easy to just throw it over to them to find the errors.”  [EDIT: please note that this was subjective opinion, I chose to include it in this post because of the stark contrast that this draws with standard development practice at other companies]
  • [CORRECTION thx epriest“We have automated testing, including “push-blocking” tests which must pass before the release goes out. We absolutely do not believe “most engineers are capable of writing bug-free code”, much less that this is a reasonable notion to base a business upon.”
  • re: surprise at lack of PM influence/control — product managers have a lot of independence and freedom.  The key to being influential is to have really good relationships with engineering managers.  Need to be technical enough not to suggest stupid ideas.  Aside from that, there’s no need to ask for any permission or pass any reviews when establishing roadmaps/backlogs.  There are relatively few PMs, but they all feel like they have responsibility for a really important and personally-interesting area of the company.
  • by default all code commits get packaged into weekly releases (tuesdays)
  • with extra effort, changes can go out same day
  • tuesday code releases require all engineers who committed code in that week’s release candidate to be on-site
  • engineers must be present in a specific IRC channel for “roll call” before the release begins or else suffer a public “shaming”
  • ops team runs code releases by gradually rolling code out
    • facebook has around 60,000 servers
    • there are 9 concentric levels for rolling out new code
    • [CORRECTION thx epriest“The nine push phases are not concentric. There are three concentric phases (p1 = internal release, p2 = small external release, p3 = full external release). The other six phases are auxiliary tiers like our internal tools, video upload hosts, etc.”
    • the smallest level is only 6 servers
    • e.g., new tuesday release is rolled out to 6 servers (level 1), ops team then observes those 6 servers and make sure that they are behaving correctly before rolling forward to the next level.
    • if a release is causing any issues (e.g., throwing errors, etc.) then push is halted.  the engineer who committed the offending changeset is paged to fix the problem.  and then the release starts over again at level 1.
    • so a release may go thru levels repeatedly:  1-2-3-fix. back to 1. 1-2-3-4-5-fix.  back to 1.  1-2-3-4-5-6-7-8-9.
  • ops team is really well-trained, well-respected, and very business-aware.  their server metrics go beyond the usual error logs, load & memory utilization stats — also include user behavior.  E.g., if a new release changes the percentage of users who engage with Facebook features, the ops team will see that in their metrics and may stop a release for that reason so they can investigate.
  • during the release process, ops team uses an IRC-based paging system that can ping individual engineers via Facebook, email, IRC, IM, and SMS if needed to get their attention.  not responding to ops team results in public shaming.
  • once code has rolled out to level 9 and is stable, then done with weekly push.
  • if a feature doesn’t get coded in time for a particular weekly push, it’s not that big a deal (unless there are hard external dependencies) — features will just generally get shipped whenever they’re completed.
  • getting svn-blamed, publicly shamed, or slipping projects too often will result in an engineer getting fired.  ”it’s a very high performance culture”.  people that aren’t productive or aren’t super talented really stick out.  Managers will literally take poor performers aside within 6 months of hiring and say “this just isn’t working out, you’re not a good culture fit”.  this actually applies at every level of the company, even C-level and VP-level hires have been quickly dismissed if they aren’t super productive.
  • [CORRECTION, thx epriest]  “People do not get called out for introducing bugs. They only get called out if they ask for changes to go out with the release but aren’t around to support them in case something goes wrong (and haven’t found someone to cover for you).”
  • [CORRECTION, thx epriest“Getting blamed will NOT get you fired. We are extremely forgiving in this respect, and most of the senior engineers have pushed at least one horrible thing, myself included. As far as I know, no one has ever been fired for making mistakes of this nature.”
  • [CORRECTION, thx fryfrog] “I also don’t know of anyone who has been fired for making mistakes like are mentioned in the article. I know of people who have inadvertently taken down the site. They work hard to fix what ever caused the problem and everyone learns from it. The public shaming is far more effective than fear of being fired, in my opinion.”

It’ll be super interesting to see how Facebook’s development culture evolves over time — and especially to see if the culture can continue scaling as the company grows into the thousands-of-employees.

What do you think?  Would “developer-driven culture” work at your company?

发表在 未分类 | 标签为 | 留下评论