blob: 5a475af8fe3bd0f63306a2b29895e972b6cfab5a [file] [log] [blame] [view]
Jamie Hannafordd5a1cb72014-10-07 14:31:27 +02001# Contributing to gophercloud
2
Jamie Hannafordd2b6dfc2014-10-07 14:46:55 +02003- [Getting started](#getting-started)
4- [Tests](#tests)
5- [Style guide](#basic-style-guide)
6- [4 ways to get involved](#4-ways-to-get-involved)
7
Jamie Hannafordd5a1cb72014-10-07 14:31:27 +02008## Getting started
9
10There should be no fundamental differences of setup between contributors and
11normal end-users. The only thing to bear in mind is that you will need to add a
12few extra environment variables for acceptance tests - this is documented in
13our [acceptance tests readme](/acceptance).
14
15## Tests
16
17When working on a new or existing feature, testing will be the backbone of your
18work since it helps uncover and prevent regressions in the codebase. There are
19two types of test we use in gophercloud: unit tests and acceptance tests, which
20are both described below.
21
22### Unit tests
23
24Unit tests are the fine-grained tests that establish and ensure the behaviour
25of individual units of functionality. We usually test on an
26operation-by-operation basis (an operation typically being an API action) with
27the use of mocking to set up explicit expectations. Each operation will set up
28its HTTP response expectation, and then test how the system responds when fed
29this controlled, pre-determined input.
30
31To make life easier, we've introduced a bunch of test helpers to simplify the
32process of testing expectations with assertions:
33
34```go
35import (
36 "testing"
37
38 "github.com/rackspace/gophercloud/testhelper"
39)
40
Jamie Hannafordd5a1cb72014-10-07 14:31:27 +020041func TestSomething(t *testing.T) {
Jamie Hannafordd5a1cb72014-10-07 14:31:27 +020042 result, err := Operation()
43
44 testhelper.AssertEquals(t, "foo", result.Bar)
45 testhelper.AssertNoErr(t, err)
46}
Jamie Hannafordd2b6dfc2014-10-07 14:46:55 +020047
48func TestSomethingElse(t *testing.T) {
49 testhelper.CheckEquals(t, "expected", "actual")
50}
Jamie Hannafordd5a1cb72014-10-07 14:31:27 +020051```
52
53`AssertEquals` and `AssertNoErr` will throw a fatal error if a value does not
54match an expected value or if an error has been declared, respectively. You can
55also use `CheckEquals` and `CheckNoErr` for the same purpose; the only difference
56being that `t.Errorf` is raised rather than `t.Fatalf`.
57
58Here is a truncated example of mocked HTTP responses:
59
Jamie Hannafordd2b6dfc2014-10-07 14:46:55 +020060```go
Jamie Hannafordd5a1cb72014-10-07 14:31:27 +020061import (
62 "testing"
63
64 th "github.com/rackspace/gophercloud/testhelper"
65 fake "github.com/rackspace/gophercloud/testhelper/client"
66)
67
68func TestGet(t *testing.T) {
Jamie Hannafordd2b6dfc2014-10-07 14:46:55 +020069 // Setup the HTTP request multiplexer and server
Jamie Hannafordd5a1cb72014-10-07 14:31:27 +020070 th.SetupHTTP()
71 defer th.TeardownHTTP()
72
73 th.Mux.HandleFunc("/networks/d32019d3-bc6e-4319-9c1d-6722fc136a22", func(w http.ResponseWriter, r *http.Request) {
74 // Test we're using the correct HTTP method
Jamie Hannafordd2b6dfc2014-10-07 14:46:55 +020075 th.TestMethod(t, r, "GET")
Jamie Hannafordd5a1cb72014-10-07 14:31:27 +020076
Jamie Hannafordd2b6dfc2014-10-07 14:46:55 +020077 // Test we're setting the auth token
Jamie Hannafordd5a1cb72014-10-07 14:31:27 +020078 th.TestHeader(t, r, "X-Auth-Token", fake.TokenID)
79
Jamie Hannafordd2b6dfc2014-10-07 14:46:55 +020080 // Set the appropriate headers for our mocked response
Jamie Hannafordd5a1cb72014-10-07 14:31:27 +020081 w.Header().Add("Content-Type", "application/json")
82 w.WriteHeader(http.StatusOK)
83
Jamie Hannafordd2b6dfc2014-10-07 14:46:55 +020084 // Set the HTTP body
Jamie Hannafordd5a1cb72014-10-07 14:31:27 +020085 fmt.Fprintf(w, `
86{
87 "network": {
88 "status": "ACTIVE",
89 "name": "private-network",
90 "admin_state_up": true,
91 "tenant_id": "4fd44f30292945e481c7b8a0c8908869",
92 "shared": true,
93 "id": "d32019d3-bc6e-4319-9c1d-6722fc136a22"
94 }
95}
96 `)
97 })
98
Jamie Hannafordd2b6dfc2014-10-07 14:46:55 +020099 // Call our API operation
Jamie Hannafordd5a1cb72014-10-07 14:31:27 +0200100 network, err := Get(fake.ServiceClient(), "d32019d3-bc6e-4319-9c1d-6722fc136a22").Extract()
101
Jamie Hannafordd2b6dfc2014-10-07 14:46:55 +0200102 // Assert no errors and equality
Jamie Hannafordd5a1cb72014-10-07 14:31:27 +0200103 th.AssertNoErr(t, err)
104 th.AssertEquals(t, n.Status, "ACTIVE")
105}
106```
107
Jamie Hannafordd2b6dfc2014-10-07 14:46:55 +0200108### Acceptance tests
Jamie Hannafordd5a1cb72014-10-07 14:31:27 +0200109
110As we've already mentioned, unit tests have a very narrow and confined focus -
111they test small units of behaviour. Acceptance tests on the other hand have a
112far larger scope: they are fully functional tests that test the entire API of a
Jamie Hannafordd2b6dfc2014-10-07 14:46:55 +0200113service in one fell swoop. They don't care about unit isolation or mocking
Jamie Hannafordd5a1cb72014-10-07 14:31:27 +0200114expectations, they instead do a full run-through and consequently test how the
115entire system _integrates_ together. When an API satisfies expectations, it
116proves by default that the requirements for a contract have been met.
117
118### Running tests
119
120To run all tests:
121
122```bash
123go test ./...
124```
125
126To run all tests with verbose output:
127
128```bash
129go test -v ./...
130```
131
132To run tests that match certain [build tags]():
133
134```bash
135go test -tags "foo bar" ./...
136```
137
138To run tests for a particular sub-package:
139
140```bash
141cd ./path/to/package && go test .
142```
143
144## Basic style guide
145
146We follow the standard formatting recommendations and language idioms set out
147in the [Effective Go](https://golang.org/doc/effective_go.html) guide. It's
148definitely worth reading - but the relevant sections are
149[formatting](https://golang.org/doc/effective_go.html#formatting)
150and [names](https://golang.org/doc/effective_go.html#names).
151
152## 4 ways to get involved
153
154There are four main ways you can get involved in our open-source project, and
155each is described briefly below. Once you've made up your mind and decided on
156your fix, you will need to follow the same basic steps that all submissions are
157required to adhere to:
158
1591. [fork](https://help.github.com/articles/fork-a-repo/) the `rackspace/gophercloud` repository
1602. checkout a [new branch](https://github.com/Kunena/Kunena-Forum/wiki/Create-a-new-branch-with-git-and-manage-branches)
1613. ensure all your commits are [well-organized](https://help.github.com/articles/about-git-rebase/)
1624. submit your branch as a [pull request](https://help.github.com/articles/creating-a-pull-request/)
163
164### 1. Fixing bugs
165
166If you want to start fixing open bugs, we'd really appreciate that! Bug fixing
167is central to any project. The best way to get started is by heading to our
168[bug tracker](https://github.com/rackspace/gophercloud/issues) and finding open
169bugs that you think nobody is working on. It might be useful to comment on the
170thread to see the current state of the issue and if anybody has made any
171breakthroughs on it so far.
172
173### 2. Improving documentation
174
175We have three forms of documentation:
176
177* short README documents that briefly introduce a topic
Jamie Hannafordd2b6dfc2014-10-07 14:46:55 +0200178* reference documentation on [godoc.org](http://godoc.org) that is automatically
179generated from source code comments
Jamie Hannafordd5a1cb72014-10-07 14:31:27 +0200180* user documentation on our [homepage](http://gophercloud.io) that includes
181getting started guides, installation guides and code samples
182
183If you feel that a certain section could be improved - whether its to clarify
Jamie Hannafordd2b6dfc2014-10-07 14:46:55 +0200184ambiguity or fix a grammatical mistake - please feel entitled to do so! We
Jamie Hannafordd5a1cb72014-10-07 14:31:27 +0200185welcome doc pull requests with the same childlike enthusiasm as any other
186contribution!
187
188### 3. Optimizing existing features
189
190If you would like to improve or optimize an existing feature, please be aware
Jamie Hannafordd2b6dfc2014-10-07 14:46:55 +0200191that we adhere to [semantic versioning](http://semver.org) - which means that
192we cannot introduce breaking changes to the API without a major version change
193(v1.x -> v2.x). Making that leap is a big step, so we encourage contributors to
194refactor rather than rewrite. Running tests will prevent regression and avoid
195the possibility of breaking somebody's current implementation.
Jamie Hannafordd5a1cb72014-10-07 14:31:27 +0200196
197### 4. Working on a new feature
198
199If you've found something we've left out, definitely feel free to start work on
200introducing that feature. It's always useful to open an issue first to indicate
201your intent to a core contributor - this enables quick feedback and can help
202steer you in the right direction by avoiding known issues. It might also help
203you avoid losing time implementing something that might not ever work.
204
205You must ensure that all of your work is well tested - both in terms of unit
206and acceptance tests. Untested code will not be merged because it introduces
Jamie Hannafordd2b6dfc2014-10-07 14:46:55 +0200207too much of a risk to end-users.
208
209Happy hacking!