| jrperritt | 94ae0eb | 2016-07-11 22:53:34 -0500 | [diff] [blame] | 1 | # Contributing to Gophercloud |
| Jamie Hannaford | d5a1cb7 | 2014-10-07 14:31:27 +0200 | [diff] [blame] | 2 | |
| Jamie Hannaford | d2b6dfc | 2014-10-07 14:46:55 +0200 | [diff] [blame] | 3 | - [Getting started](#getting-started) |
| 4 | - [Tests](#tests) |
| 5 | - [Style guide](#basic-style-guide) |
| jrperritt | 94ae0eb | 2016-07-11 22:53:34 -0500 | [diff] [blame] | 6 | - [3 ways to get involved](#5-ways-to-get-involved) |
| Jamie Hannaford | d2b6dfc | 2014-10-07 14:46:55 +0200 | [diff] [blame] | 7 | |
| Jamie Hannaford | d2773f2 | 2014-10-07 16:06:23 +0200 | [diff] [blame] | 8 | ## Setting up your git workspace |
| Jamie Hannaford | d5a1cb7 | 2014-10-07 14:31:27 +0200 | [diff] [blame] | 9 | |
| Jamie Hannaford | d2773f2 | 2014-10-07 16:06:23 +0200 | [diff] [blame] | 10 | As a contributor you will need to setup your workspace in a slightly different |
| 11 | way than just downloading it. Here are the basic installation instructions: |
| 12 | |
| Jamie Hannaford | bc35d05 | 2014-10-07 16:27:30 +0200 | [diff] [blame] | 13 | 1. Configure your `$GOPATH` and run `go get` as described in the main |
| Rickard von Essen | f66314b | 2016-02-13 11:35:00 +0100 | [diff] [blame] | 14 | [README](/README.md#how-to-install) but add `-tags "fixtures acceptance"` to |
| 15 | get dependencies for unit and acceptance tests. |
| Jamie Hannaford | d2773f2 | 2014-10-07 16:06:23 +0200 | [diff] [blame] | 16 | |
| Carolyn Van Slyck | 3084644 | 2016-07-18 15:03:14 -0500 | [diff] [blame] | 17 | ```bash |
| Krzysztof Szukiełojć | 3f41d08 | 2017-05-07 14:43:06 +0200 | [diff] [blame] | 18 | go get -tags "fixtures acceptance" gerrit.mcp.mirantis.net/debian/gophercloud.git |
| Carolyn Van Slyck | 3084644 | 2016-07-18 15:03:14 -0500 | [diff] [blame] | 19 | ``` |
| 20 | |
| Jamie Hannaford | d2773f2 | 2014-10-07 16:06:23 +0200 | [diff] [blame] | 21 | 2. Move into the directory that houses your local repository: |
| 22 | |
| Jamie Hannaford | 54bbe99 | 2014-10-07 16:50:32 +0200 | [diff] [blame] | 23 | ```bash |
| Krzysztof Szukiełojć | 3f41d08 | 2017-05-07 14:43:06 +0200 | [diff] [blame] | 24 | cd ${GOPATH}/src/gerrit.mcp.mirantis.net/debian/gophercloud.git |
| Jamie Hannaford | 54bbe99 | 2014-10-07 16:50:32 +0200 | [diff] [blame] | 25 | ``` |
| Jamie Hannaford | d2773f2 | 2014-10-07 16:06:23 +0200 | [diff] [blame] | 26 | |
| jrperritt | 55fb584 | 2016-04-13 14:16:08 -0500 | [diff] [blame] | 27 | 3. Fork the `gophercloud/gophercloud` repository and update your remote refs. You |
| Jamie Hannaford | d2773f2 | 2014-10-07 16:06:23 +0200 | [diff] [blame] | 28 | will need to rename the `origin` remote branch to `upstream`, and add your |
| 29 | fork as `origin` instead: |
| 30 | |
| Jamie Hannaford | 54bbe99 | 2014-10-07 16:50:32 +0200 | [diff] [blame] | 31 | ```bash |
| 32 | git remote rename origin upstream |
| Carolyn Van Slyck | 3084644 | 2016-07-18 15:03:14 -0500 | [diff] [blame] | 33 | git remote add origin git@github.com:<my_username>/gophercloud.git |
| Jamie Hannaford | 54bbe99 | 2014-10-07 16:50:32 +0200 | [diff] [blame] | 34 | ``` |
| Jamie Hannaford | d2773f2 | 2014-10-07 16:06:23 +0200 | [diff] [blame] | 35 | |
| jrperritt | 1d8b6f1 | 2015-08-14 12:17:09 -0600 | [diff] [blame] | 36 | 4. Checkout the latest development branch: |
| Jamie Hannaford | d2773f2 | 2014-10-07 16:06:23 +0200 | [diff] [blame] | 37 | |
| Jamie Hannaford | 54bbe99 | 2014-10-07 16:50:32 +0200 | [diff] [blame] | 38 | ```bash |
| jrperritt | 1d8b6f1 | 2015-08-14 12:17:09 -0600 | [diff] [blame] | 39 | git checkout master |
| Jamie Hannaford | 54bbe99 | 2014-10-07 16:50:32 +0200 | [diff] [blame] | 40 | ``` |
| Jamie Hannaford | d2773f2 | 2014-10-07 16:06:23 +0200 | [diff] [blame] | 41 | |
| 42 | 5. If you're working on something (discussed more in detail below), you will |
| 43 | need to checkout a new feature branch: |
| 44 | |
| Jamie Hannaford | 54bbe99 | 2014-10-07 16:50:32 +0200 | [diff] [blame] | 45 | ```bash |
| 46 | git checkout -b my-new-feature |
| 47 | ``` |
| Jamie Hannaford | d2773f2 | 2014-10-07 16:06:23 +0200 | [diff] [blame] | 48 | |
| 49 | Another thing to bear in mind is that you will need to add a few extra |
| 50 | environment variables for acceptance tests - this is documented in our |
| 51 | [acceptance tests readme](/acceptance). |
| Jamie Hannaford | d5a1cb7 | 2014-10-07 14:31:27 +0200 | [diff] [blame] | 52 | |
| 53 | ## Tests |
| 54 | |
| 55 | When working on a new or existing feature, testing will be the backbone of your |
| 56 | work since it helps uncover and prevent regressions in the codebase. There are |
| jrperritt | 55fb584 | 2016-04-13 14:16:08 -0500 | [diff] [blame] | 57 | two types of test we use in Gophercloud: unit tests and acceptance tests, which |
| Jamie Hannaford | d5a1cb7 | 2014-10-07 14:31:27 +0200 | [diff] [blame] | 58 | are both described below. |
| 59 | |
| 60 | ### Unit tests |
| 61 | |
| jrperritt | 55fb584 | 2016-04-13 14:16:08 -0500 | [diff] [blame] | 62 | Unit tests are the fine-grained tests that establish and ensure the behavior |
| Jamie Hannaford | d5a1cb7 | 2014-10-07 14:31:27 +0200 | [diff] [blame] | 63 | of individual units of functionality. We usually test on an |
| 64 | operation-by-operation basis (an operation typically being an API action) with |
| 65 | the use of mocking to set up explicit expectations. Each operation will set up |
| 66 | its HTTP response expectation, and then test how the system responds when fed |
| 67 | this controlled, pre-determined input. |
| 68 | |
| 69 | To make life easier, we've introduced a bunch of test helpers to simplify the |
| 70 | process of testing expectations with assertions: |
| 71 | |
| 72 | ```go |
| 73 | import ( |
| 74 | "testing" |
| 75 | |
| Krzysztof Szukiełojć | 24a29ce | 2017-05-07 14:24:02 +0200 | [diff] [blame] | 76 | "gerrit.mcp.mirantis.net/debian/gophercloud.git/testhelper" |
| Jamie Hannaford | d5a1cb7 | 2014-10-07 14:31:27 +0200 | [diff] [blame] | 77 | ) |
| 78 | |
| Jamie Hannaford | d5a1cb7 | 2014-10-07 14:31:27 +0200 | [diff] [blame] | 79 | func TestSomething(t *testing.T) { |
| Jamie Hannaford | d5a1cb7 | 2014-10-07 14:31:27 +0200 | [diff] [blame] | 80 | result, err := Operation() |
| 81 | |
| 82 | testhelper.AssertEquals(t, "foo", result.Bar) |
| 83 | testhelper.AssertNoErr(t, err) |
| 84 | } |
| Jamie Hannaford | d2b6dfc | 2014-10-07 14:46:55 +0200 | [diff] [blame] | 85 | |
| 86 | func TestSomethingElse(t *testing.T) { |
| 87 | testhelper.CheckEquals(t, "expected", "actual") |
| 88 | } |
| Jamie Hannaford | d5a1cb7 | 2014-10-07 14:31:27 +0200 | [diff] [blame] | 89 | ``` |
| 90 | |
| 91 | `AssertEquals` and `AssertNoErr` will throw a fatal error if a value does not |
| 92 | match an expected value or if an error has been declared, respectively. You can |
| 93 | also use `CheckEquals` and `CheckNoErr` for the same purpose; the only difference |
| 94 | being that `t.Errorf` is raised rather than `t.Fatalf`. |
| 95 | |
| 96 | Here is a truncated example of mocked HTTP responses: |
| 97 | |
| Jamie Hannaford | d2b6dfc | 2014-10-07 14:46:55 +0200 | [diff] [blame] | 98 | ```go |
| Jamie Hannaford | d5a1cb7 | 2014-10-07 14:31:27 +0200 | [diff] [blame] | 99 | import ( |
| 100 | "testing" |
| 101 | |
| Krzysztof Szukiełojć | 24a29ce | 2017-05-07 14:24:02 +0200 | [diff] [blame] | 102 | th "gerrit.mcp.mirantis.net/debian/gophercloud.git/testhelper" |
| 103 | fake "gerrit.mcp.mirantis.net/debian/gophercloud.git/testhelper/client" |
| 104 | "gerrit.mcp.mirantis.net/debian/gophercloud.git/openstack/networking/v2/networks" |
| Jamie Hannaford | d5a1cb7 | 2014-10-07 14:31:27 +0200 | [diff] [blame] | 105 | ) |
| 106 | |
| 107 | func TestGet(t *testing.T) { |
| Jamie Hannaford | d2b6dfc | 2014-10-07 14:46:55 +0200 | [diff] [blame] | 108 | // Setup the HTTP request multiplexer and server |
| Jamie Hannaford | d5a1cb7 | 2014-10-07 14:31:27 +0200 | [diff] [blame] | 109 | th.SetupHTTP() |
| 110 | defer th.TeardownHTTP() |
| 111 | |
| 112 | th.Mux.HandleFunc("/networks/d32019d3-bc6e-4319-9c1d-6722fc136a22", func(w http.ResponseWriter, r *http.Request) { |
| 113 | // Test we're using the correct HTTP method |
| Jamie Hannaford | d2b6dfc | 2014-10-07 14:46:55 +0200 | [diff] [blame] | 114 | th.TestMethod(t, r, "GET") |
| Jamie Hannaford | d5a1cb7 | 2014-10-07 14:31:27 +0200 | [diff] [blame] | 115 | |
| Jamie Hannaford | d2b6dfc | 2014-10-07 14:46:55 +0200 | [diff] [blame] | 116 | // Test we're setting the auth token |
| Jamie Hannaford | d5a1cb7 | 2014-10-07 14:31:27 +0200 | [diff] [blame] | 117 | th.TestHeader(t, r, "X-Auth-Token", fake.TokenID) |
| 118 | |
| Jamie Hannaford | d2b6dfc | 2014-10-07 14:46:55 +0200 | [diff] [blame] | 119 | // Set the appropriate headers for our mocked response |
| Jamie Hannaford | d5a1cb7 | 2014-10-07 14:31:27 +0200 | [diff] [blame] | 120 | w.Header().Add("Content-Type", "application/json") |
| 121 | w.WriteHeader(http.StatusOK) |
| 122 | |
| Jamie Hannaford | d2b6dfc | 2014-10-07 14:46:55 +0200 | [diff] [blame] | 123 | // Set the HTTP body |
| Jamie Hannaford | d5a1cb7 | 2014-10-07 14:31:27 +0200 | [diff] [blame] | 124 | fmt.Fprintf(w, ` |
| 125 | { |
| 126 | "network": { |
| 127 | "status": "ACTIVE", |
| 128 | "name": "private-network", |
| 129 | "admin_state_up": true, |
| 130 | "tenant_id": "4fd44f30292945e481c7b8a0c8908869", |
| 131 | "shared": true, |
| 132 | "id": "d32019d3-bc6e-4319-9c1d-6722fc136a22" |
| 133 | } |
| 134 | } |
| 135 | `) |
| 136 | }) |
| 137 | |
| Jamie Hannaford | d2b6dfc | 2014-10-07 14:46:55 +0200 | [diff] [blame] | 138 | // Call our API operation |
| jrperritt | 94ae0eb | 2016-07-11 22:53:34 -0500 | [diff] [blame] | 139 | network, err := networks.Get(fake.ServiceClient(), "d32019d3-bc6e-4319-9c1d-6722fc136a22").Extract() |
| Jamie Hannaford | d5a1cb7 | 2014-10-07 14:31:27 +0200 | [diff] [blame] | 140 | |
| Jamie Hannaford | d2b6dfc | 2014-10-07 14:46:55 +0200 | [diff] [blame] | 141 | // Assert no errors and equality |
| Jamie Hannaford | d5a1cb7 | 2014-10-07 14:31:27 +0200 | [diff] [blame] | 142 | th.AssertNoErr(t, err) |
| 143 | th.AssertEquals(t, n.Status, "ACTIVE") |
| 144 | } |
| 145 | ``` |
| 146 | |
| Jamie Hannaford | d2b6dfc | 2014-10-07 14:46:55 +0200 | [diff] [blame] | 147 | ### Acceptance tests |
| Jamie Hannaford | d5a1cb7 | 2014-10-07 14:31:27 +0200 | [diff] [blame] | 148 | |
| 149 | As we've already mentioned, unit tests have a very narrow and confined focus - |
| jrperritt | 55fb584 | 2016-04-13 14:16:08 -0500 | [diff] [blame] | 150 | they test small units of behavior. Acceptance tests on the other hand have a |
| Jamie Hannaford | d5a1cb7 | 2014-10-07 14:31:27 +0200 | [diff] [blame] | 151 | far larger scope: they are fully functional tests that test the entire API of a |
| Jamie Hannaford | d2b6dfc | 2014-10-07 14:46:55 +0200 | [diff] [blame] | 152 | service in one fell swoop. They don't care about unit isolation or mocking |
| Jamie Hannaford | d5a1cb7 | 2014-10-07 14:31:27 +0200 | [diff] [blame] | 153 | expectations, they instead do a full run-through and consequently test how the |
| 154 | entire system _integrates_ together. When an API satisfies expectations, it |
| 155 | proves by default that the requirements for a contract have been met. |
| 156 | |
| Jamie Hannaford | d2773f2 | 2014-10-07 16:06:23 +0200 | [diff] [blame] | 157 | Please be aware that acceptance tests will hit a live API - and may incur |
| 158 | service charges from your provider. Although most tests handle their own |
| 159 | teardown procedures, it is always worth manually checking that resources are |
| 160 | deleted after the test suite finishes. |
| 161 | |
| Jamie Hannaford | d5a1cb7 | 2014-10-07 14:31:27 +0200 | [diff] [blame] | 162 | ### Running tests |
| 163 | |
| 164 | To run all tests: |
| 165 | |
| 166 | ```bash |
| Rickard von Essen | f66314b | 2016-02-13 11:35:00 +0100 | [diff] [blame] | 167 | go test -tags fixtures ./... |
| Jamie Hannaford | d5a1cb7 | 2014-10-07 14:31:27 +0200 | [diff] [blame] | 168 | ``` |
| 169 | |
| 170 | To run all tests with verbose output: |
| 171 | |
| 172 | ```bash |
| Rickard von Essen | f66314b | 2016-02-13 11:35:00 +0100 | [diff] [blame] | 173 | go test -v -tags fixtures ./... |
| Jamie Hannaford | d5a1cb7 | 2014-10-07 14:31:27 +0200 | [diff] [blame] | 174 | ``` |
| 175 | |
| 176 | To run tests that match certain [build tags](): |
| 177 | |
| 178 | ```bash |
| Rickard von Essen | f66314b | 2016-02-13 11:35:00 +0100 | [diff] [blame] | 179 | go test -tags "fixtures foo bar" ./... |
| Jamie Hannaford | d5a1cb7 | 2014-10-07 14:31:27 +0200 | [diff] [blame] | 180 | ``` |
| 181 | |
| 182 | To run tests for a particular sub-package: |
| 183 | |
| 184 | ```bash |
| Rickard von Essen | f66314b | 2016-02-13 11:35:00 +0100 | [diff] [blame] | 185 | cd ./path/to/package && go test -tags fixtures . |
| Jamie Hannaford | d5a1cb7 | 2014-10-07 14:31:27 +0200 | [diff] [blame] | 186 | ``` |
| 187 | |
| jrperritt | 55fb584 | 2016-04-13 14:16:08 -0500 | [diff] [blame] | 188 | ## Style guide |
| 189 | |
| jrperritt | 9b7b9e6 | 2016-07-11 22:30:50 -0500 | [diff] [blame] | 190 | See [here](/STYLEGUIDE.md) |
| jrperritt | 55fb584 | 2016-04-13 14:16:08 -0500 | [diff] [blame] | 191 | |
| jrperritt | 9b7b9e6 | 2016-07-11 22:30:50 -0500 | [diff] [blame] | 192 | ## 3 ways to get involved |
| Jamie Hannaford | d5a1cb7 | 2014-10-07 14:31:27 +0200 | [diff] [blame] | 193 | |
| Jamie Hannaford | d2773f2 | 2014-10-07 16:06:23 +0200 | [diff] [blame] | 194 | There are five main ways you can get involved in our open-source project, and |
| Jamie Hannaford | d5a1cb7 | 2014-10-07 14:31:27 +0200 | [diff] [blame] | 195 | each is described briefly below. Once you've made up your mind and decided on |
| 196 | your fix, you will need to follow the same basic steps that all submissions are |
| 197 | required to adhere to: |
| 198 | |
| jrperritt | 55fb584 | 2016-04-13 14:16:08 -0500 | [diff] [blame] | 199 | 1. [fork](https://help.github.com/articles/fork-a-repo/) the `gophercloud/gophercloud` repository |
| Jamie Hannaford | d5a1cb7 | 2014-10-07 14:31:27 +0200 | [diff] [blame] | 200 | 2. checkout a [new branch](https://github.com/Kunena/Kunena-Forum/wiki/Create-a-new-branch-with-git-and-manage-branches) |
| Jamie Hannaford | d2773f2 | 2014-10-07 16:06:23 +0200 | [diff] [blame] | 201 | 3. submit your branch as a [pull request](https://help.github.com/articles/creating-a-pull-request/) |
| Jamie Hannaford | d5a1cb7 | 2014-10-07 14:31:27 +0200 | [diff] [blame] | 202 | |
| jrperritt | 9b7b9e6 | 2016-07-11 22:30:50 -0500 | [diff] [blame] | 203 | ### 1. Fixing bugs |
| Jamie Hannaford | d5a1cb7 | 2014-10-07 14:31:27 +0200 | [diff] [blame] | 204 | |
| 205 | If you want to start fixing open bugs, we'd really appreciate that! Bug fixing |
| 206 | is central to any project. The best way to get started is by heading to our |
| Krzysztof Szukiełojć | 24a29ce | 2017-05-07 14:24:02 +0200 | [diff] [blame] | 207 | [bug tracker](https://gerrit.mcp.mirantis.net/debian/gophercloud.git/issues) and finding open |
| Jamie Hannaford | d5a1cb7 | 2014-10-07 14:31:27 +0200 | [diff] [blame] | 208 | bugs that you think nobody is working on. It might be useful to comment on the |
| 209 | thread to see the current state of the issue and if anybody has made any |
| 210 | breakthroughs on it so far. |
| 211 | |
| jrperritt | 9b7b9e6 | 2016-07-11 22:30:50 -0500 | [diff] [blame] | 212 | ### 2. Improving documentation |
| 213 | The best source of documentation is on [godoc.org](http://godoc.org). It is |
| 214 | automatically generated from the source code. |
| Jamie Hannaford | d5a1cb7 | 2014-10-07 14:31:27 +0200 | [diff] [blame] | 215 | |
| Jamie Hannaford | bc35d05 | 2014-10-07 16:27:30 +0200 | [diff] [blame] | 216 | If you feel that a certain section could be improved - whether it's to clarify |
| 217 | ambiguity, correct a technical mistake, or to fix a grammatical error - please |
| 218 | feel entitled to do so! We welcome doc pull requests with the same childlike |
| 219 | enthusiasm as any other contribution! |
| Jamie Hannaford | d5a1cb7 | 2014-10-07 14:31:27 +0200 | [diff] [blame] | 220 | |
| jrperritt | 9b7b9e6 | 2016-07-11 22:30:50 -0500 | [diff] [blame] | 221 | ###3. Working on a new feature |
| Jamie Hannaford | d5a1cb7 | 2014-10-07 14:31:27 +0200 | [diff] [blame] | 222 | |
| 223 | If you've found something we've left out, definitely feel free to start work on |
| Jamie Hannaford | d2773f2 | 2014-10-07 16:06:23 +0200 | [diff] [blame] | 224 | introducing that feature. It's always useful to open an issue or submit a pull |
| 225 | request early on to indicate your intent to a core contributor - this enables |
| 226 | quick/early feedback and can help steer you in the right direction by avoiding |
| 227 | known issues. It might also help you avoid losing time implementing something |
| 228 | that might not ever work. One tip is to prefix your Pull Request issue title |
| 229 | with [wip] - then people know it's a work in progress. |
| Jamie Hannaford | d5a1cb7 | 2014-10-07 14:31:27 +0200 | [diff] [blame] | 230 | |
| 231 | You must ensure that all of your work is well tested - both in terms of unit |
| 232 | and acceptance tests. Untested code will not be merged because it introduces |
| Jamie Hannaford | d2b6dfc | 2014-10-07 14:46:55 +0200 | [diff] [blame] | 233 | too much of a risk to end-users. |
| 234 | |
| 235 | Happy hacking! |