Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Internal master #6790

Merged
merged 2 commits into from
Jan 10, 2020
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
17 changes: 14 additions & 3 deletions azure-pipelines.yml
Original file line number Diff line number Diff line change
@@ -1,3 +1,13 @@
trigger:
paths:
exclude:
- sdk/

pr:
paths:
exclude:
- sdk/

jobs:
- job: Build_Test
strategy:
Expand All @@ -18,6 +28,7 @@ jobs:
GOPATH: '$(system.defaultWorkingDirectory)/work'
sdkPath: '$(GOPATH)/src/github.com/$(build.repository.name)'
IGNORE_BREAKING_CHANGES: true
go.list.filter: 'grep -v vendor | grep -v azure-sdk-for-go/sdk'

steps:
- script: |
Expand All @@ -37,13 +48,13 @@ jobs:
go get -u golang.org/x/lint/golint
workingDirectory: '$(sdkPath)'
displayName: 'Install Dependencies'
- script: go vet $(go list ./... | grep -v vendor)
- script: go vet $(go list ./... $(go.list.filter))
workingDirectory: '$(sdkPath)'
displayName: 'Vet'
- script: go build -v $(go list ./... | grep -v vendor)
- script: go build -v $(go list ./... $(go.list.filter))
workingDirectory: '$(sdkPath)'
displayName: 'Build'
- script: go test $(dirname $(find . -path ./vendor -prune -o -name '*_test.go' -print) | sort -u)
- script: go test $(dirname $(find . -path ./vendor -prune -o -path ./sdk -prune -o -name '*_test.go' -print) | sort -u)
workingDirectory: '$(sdkPath)'
displayName: 'Run Tests'
- script: go run ./tools/apidiff/main.go packages ./services FETCH_HEAD~1 FETCH_HEAD --copyrepo --breakingchanges || $IGNORE_BREAKING_CHANGES
Expand Down
67 changes: 67 additions & 0 deletions sdk/ci.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,67 @@
trigger:
paths:
include:
- sdk/

pr:
paths:
include:
- sdk/

jobs:
- job: Build_Test
strategy:
matrix:
Linux_Go113:
vm.image: 'ubuntu-18.04'
go.version: '1.13'
GOROOT: '/usr/local/go$(go.version)'

pool:
vmImage: $(vm.image)

variables:
GOPATH: '$(system.defaultWorkingDirectory)/work'
sdkPath: '$(GOPATH)/src/github.com/$(build.repository.name)'

steps:
- script: |
set -e
mkdir -p '$(GOPATH)/bin'
mkdir -p '$(sdkPath)'
shopt -s dotglob extglob
mv !(work) '$(sdkPath)'
echo '##vso[task.prependpath]$(GOROOT)/bin'
echo '##vso[task.prependpath]$(GOPATH)/bin'
displayName: 'Create Go Workspace'
- script: |
set -e
go version
go get -u golang.org/x/lint/golint
workingDirectory: '$(sdkPath)'
displayName: 'Install Dependencies'
- script: go vet $(go list ./sdk/...)
workingDirectory: '$(sdkPath)'
displayName: 'Vet'
- script: go build -v $(go list ./sdk/...)
workingDirectory: '$(sdkPath)'
displayName: 'Build'
- script: go test ./sdk/...
workingDirectory: '$(sdkPath)'
displayName: 'Run Tests'
- script: grep -L -r --include \*.go -P "Copyright (\d{4}|\(c\)) Microsoft" ./sdk | tee >&2
workingDirectory: '$(sdkPath)'
displayName: 'Copyright Header Check'
failOnStderr: true
condition: succeededOrFailed()
- script: gofmt -s -l -w $(find ./sdk -name '*.go' -print) >&2
workingDirectory: '$(sdkPath)'
displayName: 'Format Check'
failOnStderr: true
condition: succeededOrFailed()
- script: |
golint ./sdk/... >&2
workingDirectory: '$(sdkPath)'
displayName: 'Linter Check'
failOnStderr: true
condition: succeededOrFailed()
76 changes: 76 additions & 0 deletions sdk/internal/atomic/atomic.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,76 @@
// Copyright (c) Microsoft Corporation. All rights reserved.
// Licensed under the MIT License.

package atomic

import (
"sync/atomic"
"time"
)

// Int64 is an atomic wrapper around an int64.
type Int64 int64

// NewInt64 creates a new Int64.
func NewInt64(i int64) Int64 {
return Int64(i)
}

// CAS is an atomic compare-and-swap.
func (i *Int64) CAS(old, new int64) bool {
return atomic.CompareAndSwapInt64((*int64)(i), old, new)
}

// Load atomically loads the value.
func (i *Int64) Load() int64 {
return atomic.LoadInt64((*int64)(i))
}

// Store atomically stores the value.
func (i *Int64) Store(v int64) {
atomic.StoreInt64((*int64)(i), v)
}

// String is an atomic wrapper around a string.
type String struct {
v atomic.Value
}

// NewString creats a new String.
func NewString(s string) *String {
ss := String{}
ss.v.Store(s)
return &ss
}

// Load atomically loads the string.
func (s *String) Load() string {
return s.v.Load().(string)
}

// Store atomically stores the string.
func (s *String) Store(v string) {
s.v.Store(v)
}

// Time is an atomic wrapper around a time.Time.
type Time struct {
v atomic.Value
}

// NewTime creates a new Time.
func NewTime(t time.Time) *Time {
tt := Time{}
tt.v.Store(t)
return &tt
}

// Load atomically loads the time.Time.
func (t *Time) Load() time.Time {
return t.v.Load().(time.Time)
}

// Store atomically stores the time.Time.
func (t *Time) Store(v time.Time) {
t.v.Store(v)
}
3 changes: 3 additions & 0 deletions sdk/internal/go.mod
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
module github.com/Azure/azure-sdk-for-go/sdk/internal

go 1.13
205 changes: 205 additions & 0 deletions sdk/internal/mock/mock.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,205 @@
// Copyright (c) Microsoft Corporation. All rights reserved.
// Licensed under the MIT License.

package mock

import (
"context"
"net/http"
"net/http/httptest"
"net/url"
)

// Server is a wrapper around an httptest.Server.
// The serving of requests is not safe for concurrent use
// which is ok for right now as each test creates is own
// server and doesn't create additional go routines.
type Server struct {
srv *httptest.Server

// static is the static response, if this is not nil it's always returned.
static *mockResponse

// resp is the queue of responses. each response is taken from the front.
resp []mockResponse

// count tracks the number of requests that have been made.
count int
}

// NewServer creates a new Server object.
// The returned close func must be called when the server is no longer needed.
func NewServer() (*Server, func()) {
s := Server{}
s.srv = httptest.NewServer(http.HandlerFunc(s.serveHTTP))
return &s, func() { s.srv.Close() }
}

// NewTLSServer creates a new Server object.
// The returned close func must be called when the server is no longer needed.
func NewTLSServer() (*Server, func()) {
s := Server{}
s.srv = httptest.NewTLSServer(http.HandlerFunc(s.serveHTTP))
return &s, func() { s.srv.Close() }
}

// returns true if the next response is an error response
func (s *Server) isErrorResp() bool {
if s.static == nil && len(s.resp) == 0 {
panic("no more responses")
}
// always favor static response
if s.static != nil && s.static.err != nil {
return true
}
if len(s.resp) == 0 {
return false
}
return s.resp[0].err != nil
}

// returns the static response or the next response in the queue
func (s *Server) getResponse() mockResponse {
if s.static == nil && len(s.resp) == 0 {
panic("no more responses")
}
// always favor static response
if s.static != nil {
return *s.static
}
// pop off first response and return it
resp := s.resp[0]
s.resp = s.resp[1:]
return resp
}

// URL returns the endpoint of the test server in URL format.
func (s *Server) URL() url.URL {
u, err := url.Parse(s.srv.URL)
if err != nil {
panic(err)
}
return *u
}

// Do implements the azcore.Transport interface on Server.
// Calling this when the response queue is empty and no static
// response has been set will cause a panic.
func (s *Server) Do(ctx context.Context, req *http.Request) (*http.Response, error) {
s.count++
// error responses are returned here
if s.isErrorResp() {
resp := s.getResponse()
return nil, resp.err
}
return s.srv.Client().Do(req.WithContext(ctx))
}

func (s *Server) serveHTTP(w http.ResponseWriter, req *http.Request) {
s.getResponse().write(w)
}

// Requests returns the number of times an HTTP request was made.
func (s *Server) Requests() int {
return s.count
}

// AppendError appends the error to the end of the response queue.
func (s *Server) AppendError(err error) {
s.resp = append(s.resp, mockResponse{err: err})
}

// RepeatError appends the error n number of times to the end of the response queue.
func (s *Server) RepeatError(n int, err error) {
for i := 0; i < n; i++ {
s.AppendError(err)
}
}

// SetError indicates the same error should always be returned.
// Any responses set via other methods will be ignored.
func (s *Server) SetError(err error) {
s.static = &mockResponse{err: err}
}

// AppendResponse appends the response to the end of the response queue.
// If no options are provided the default response is an http.StatusOK.
func (s *Server) AppendResponse(opts ...ResponseOption) {
mr := mockResponse{code: http.StatusOK}
for _, o := range opts {
o.apply(&mr)
}
s.resp = append(s.resp, mr)
}

// RepeatResponse appends the response n number of times to the end of the response queue.
// If no options are provided the default response is an http.StatusOK.
func (s *Server) RepeatResponse(n int, opts ...ResponseOption) {
for i := 0; i < n; i++ {
s.AppendResponse(opts...)
}
}

// SetResponse indicates the same response should always be returned.
// Any responses set via other methods will be ignored.
// If no options are provided the default response is an http.StatusOK.
func (s *Server) SetResponse(opts ...ResponseOption) {
mr := mockResponse{code: http.StatusOK}
for _, o := range opts {
o.apply(&mr)
}
s.static = &mr
}

// ResponseOption is an abstraction for configuring a mock HTTP response.
type ResponseOption interface {
apply(mr *mockResponse)
}

type fnRespOpt func(*mockResponse)

func (fn fnRespOpt) apply(mr *mockResponse) {
fn(mr)
}

type mockResponse struct {
code int
body []byte
headers http.Header
err error
}

func (mr mockResponse) write(w http.ResponseWriter) {
w.WriteHeader(mr.code)
if mr.body != nil {
w.Write(mr.body)
}
if len(mr.headers) > 0 {
for k, v := range mr.headers {
for _, vv := range v {
w.Header().Add(k, vv)
}
}
}
}

// WithStatusCode sets the HTTP response's status code to the specified value.
func WithStatusCode(c int) ResponseOption {
return fnRespOpt(func(mr *mockResponse) {
mr.code = c
})
}

// WithBody sets the HTTP response's body to the specified value.
func WithBody(b []byte) ResponseOption {
return fnRespOpt(func(mr *mockResponse) {
mr.body = b
})
}

// WithHeader adds the specified header and value to the HTTP response.
func WithHeader(k, v string) ResponseOption {
return fnRespOpt(func(mr *mockResponse) {
mr.headers.Add(k, v)
})
}
Loading