Add latest changes from gitlab-org/gitlab@master

This commit is contained in:
GitLab Bot 2020-10-02 06:08:27 +00:00
parent 895563036a
commit 91ef4dcc05
50 changed files with 268 additions and 525 deletions

View file

@ -1,6 +1,6 @@
<script>
import { GlAlert } from '@gitlab/ui';
import { __ } from '~/locale';
import { __, sprintf } from '~/locale';
import ServiceDeskSetting from './service_desk_setting.vue';
import ServiceDeskService from '../services/service_desk_service';
import eventHub from '../event_hub';
@ -122,11 +122,13 @@ export default {
this.incomingEmail = data?.service_desk_address;
this.showAlert(__('Changes were successfully made.'), 'success');
})
.catch(() =>
.catch(err => {
this.showAlert(
__('An error occurred while saving the template. Please check if the template exists.'),
),
)
sprintf(__('An error occured while making the changes: %{error}'), {
error: err?.response?.data?.message,
}),
);
})
.finally(() => {
this.isTemplateSaving = false;
});

View file

@ -1,5 +1,5 @@
<script>
import { GlButton, GlFormSelect, GlToggle, GlLoadingIcon } from '@gitlab/ui';
import { GlButton, GlFormSelect, GlToggle, GlLoadingIcon, GlSprintf } from '@gitlab/ui';
import { __ } from '~/locale';
import tooltip from '~/vue_shared/directives/tooltip';
import glFeatureFlagsMixin from '~/vue_shared/mixins/gl_feature_flags_mixin';
@ -17,6 +17,7 @@ export default {
GlFormSelect,
GlToggle,
GlLoadingIcon,
GlSprintf,
},
mixins: [glFeatureFlagsMixin()],
props: {
@ -60,6 +61,7 @@ export default {
selectedTemplate: this.initialSelectedTemplate,
outgoingName: this.initialOutgoingName || __('GitLab Support Bot'),
projectKey: this.initialProjectKey,
baseEmail: this.incomingEmail.replace(this.initialProjectKey, ''),
};
},
computed: {
@ -123,12 +125,33 @@ export default {
/>
</div>
</div>
<span v-if="projectKey" class="form-text text-muted">
<gl-sprintf :message="__('Emails sent to %{email} will still be supported')">
<template #email>
<code>{{ baseEmail }}</code>
</template>
</gl-sprintf>
</span>
</template>
<template v-else>
<gl-loading-icon :inline="true" />
<span class="sr-only">{{ __('Fetching incoming email') }}</span>
</template>
<template v-if="hasProjectKeySupport">
<label for="service-desk-project-suffix" class="mt-3">
{{ __('Project name suffix') }}
</label>
<input id="service-desk-project-suffix" v-model.trim="projectKey" class="form-control" />
<span class="form-text text-muted">
{{
__(
'Project name suffix is a user-defined string which will be appended to the project path, and will form the Service Desk email address.',
)
}}
</span>
</template>
<label for="service-desk-template-select" class="mt-3">
{{ __('Template to append to all Service Desk issues') }}
</label>
@ -144,19 +167,7 @@ export default {
<span class="form-text text-muted">
{{ __('Emails sent from Service Desk will have this name') }}
</span>
<template v-if="hasProjectKeySupport">
<label for="service-desk-project-suffix" class="mt-3">
{{ __('Project name suffix') }}
</label>
<input id="service-desk-project-suffix" v-model.trim="projectKey" class="form-control" />
<span class="form-text text-muted mb-3">
{{
__(
'Project name suffix is a user-defined string which will be appended to the project path, and will form the Service Desk email address.',
)
}}
</span>
</template>
<div class="gl-display-flex gl-justify-content-end">
<gl-button
variant="success"
class="gl-mt-5"
@ -168,4 +179,5 @@ export default {
</div>
</div>
</div>
</div>
</template>

View file

@ -90,6 +90,7 @@ export default {
:size="12"
:title="stateTitle"
:aria-label="state"
data-testid="referenceIcon"
/>
{{ displayReference }}
</component>
@ -105,6 +106,7 @@ export default {
:title="removeButtonLabel"
:aria-label="removeButtonLabel"
:disabled="removeDisabled"
data-testid="removeBtn"
type="button"
class="js-issue-token-remove-button"
@click="onRemoveRequest"

View file

@ -111,7 +111,7 @@ const mixins = {
return this.isMergeRequest && this.pipelineStatus && Object.keys(this.pipelineStatus).length;
},
isOpen() {
return this.state === 'opened';
return this.state === 'opened' || this.state === 'reopened';
},
isClosed() {
return this.state === 'closed';

View file

@ -22,8 +22,8 @@ module Postgresql
def self.lag_too_great?(max = 100.megabytes)
return false unless in_use?
lag_function = "#{Gitlab::Database.pg_wal_lsn_diff}" \
"(#{Gitlab::Database.pg_current_wal_insert_lsn}(), restart_lsn)::bigint"
lag_function = "pg_wal_lsn_diff" \
"(pg_current_wal_insert_lsn(), restart_lsn)::bigint"
# We force the use of a transaction here so the query always goes to the
# primary, even when using the EE DB load balancer.

View file

@ -1,4 +1,5 @@
- add_page_startup_api_call discussions_path(@issue)
- add_page_startup_api_call notes_url
- @gfm_form = true

View file

@ -1,5 +0,0 @@
---
redirect_to: '../administration/geo/replication/using_a_geo_server.md'
---
This document was moved to [another location](../administration/geo/replication/using_a_geo_server.md).

View file

@ -1,5 +0,0 @@
---
redirect_to: '../administration/geo/disaster_recovery/bring_primary_back.md'
---
This document was moved to [another location](../administration/geo/disaster_recovery/bring_primary_back.md).

View file

@ -1,5 +0,0 @@
---
redirect_to: '../administration/geo/replication/configuration.md'
---
This document was moved to [another location](../administration/geo/replication/configuration.md).

View file

@ -1,5 +0,0 @@
---
redirect_to: '../administration/geo/replication/configuration.md'
---
This document was moved to [another location](../administration/geo/replication/configuration.md).

View file

@ -1,5 +0,0 @@
---
redirect_to: '../administration/geo/setup/database.md'
---
This document was moved to [another location](../administration/geo/setup/database.md).

View file

@ -1,5 +0,0 @@
---
redirect_to: '../administration/geo/setup/database.md'
---
This document was moved to [another location](../administration/geo/setup/database.md).

View file

@ -1,5 +0,0 @@
---
redirect_to: '../administration/geo/disaster_recovery/index.md'
---
This document was moved to [another location](../administration/geo/disaster_recovery/index.md).

View file

@ -1,5 +0,0 @@
---
redirect_to: '../administration/geo/replication/docker_registry.md'
---
This document was moved to [another location](../administration/geo/replication/docker_registry.md).

View file

@ -1,5 +0,0 @@
---
redirect_to: '../administration/geo/replication/faq.md'
---
This document was moved to [another location](../administration/geo/replication/faq.md).

View file

@ -1,5 +0,0 @@
---
redirect_to: '../administration/geo/replication/multiple_servers.md'
---
This document was moved to [another location](../administration/geo/replication/multiple_servers.md).

View file

@ -1,5 +0,0 @@
---
redirect_to: '../administration/geo/replication/object_storage.md'
---
This document was moved to [another location](../administration/geo/replication/object_storage.md).

View file

@ -1,5 +0,0 @@
---
redirect_to: '../administration/geo/disaster_recovery/planned_failover.md'
---
This document was moved to [another location](../administration/geo/disaster_recovery/planned_failover.md).

View file

@ -1,5 +0,0 @@
---
redirect_to: '../administration/geo/replication/security_review.md'
---
This document was moved to [another location](../administration/geo/replication/security_review.md).

View file

@ -1,5 +0,0 @@
---
redirect_to: '../administration/operations/fast_ssh_key_lookup.md'
---
This document was moved to [another location](../administration/operations/fast_ssh_key_lookup.md).

View file

@ -1,5 +0,0 @@
---
redirect_to: '../administration/geo/replication/troubleshooting.md'
---
This document was moved to [another location](../administration/geo/replication/troubleshooting.md).

View file

@ -1,5 +0,0 @@
---
redirect_to: '../administration/geo/replication/tuning.md'
---
This document was moved to [another location](../administration/geo/replication/tuning.md).

View file

@ -1,5 +0,0 @@
---
redirect_to: '../administration/geo/replication/updating_the_geo_nodes.md'
---
This document was moved to [another location](../administration/geo/replication/updating_the_geo_nodes.md).

View file

@ -1,5 +0,0 @@
---
redirect_to: '../administration/geo/replication/using_a_geo_server.md'
---
This document was moved to [another location](../administration/geo/replication/using_a_geo_server.md).

View file

@ -48,7 +48,7 @@ To enable the CAS OmniAuth provider you must register your application with your
url: 'CAS_SERVER',
login_url: '/CAS_PATH/login',
service_validate_url: '/CAS_PATH/p3/serviceValidate',
logout_url: '/CAS_PATH/logout'} }
logout_url: '/CAS_PATH/logout' } }
```
1. Change 'CAS_PATH' to the root of your CAS instance (ie. `cas`).

View file

@ -78,7 +78,8 @@ Follow these steps to incorporate the GitHub OAuth 2 app in your GitLab server:
For GitHub Enterprise:
```yaml
- { name: 'github', app_id: 'YOUR_APP_ID',
- { name: 'github',
app_id: 'YOUR_APP_ID',
app_secret: 'YOUR_APP_SECRET',
url: "https://github.example.com/",
args: { scope: 'user:email' } }
@ -125,7 +126,8 @@ omnibus_gitconfig['system'] = { "http" => ["sslVerify = false"] }
For installation from source:
```yaml
- { name: 'github', app_id: 'YOUR_APP_ID',
- { name: 'github',
app_id: 'YOUR_APP_ID',
app_secret: 'YOUR_APP_SECRET',
url: "https://github.example.com/",
verify_ssl: false,

View file

@ -63,7 +63,8 @@ GitLab.com will generate an application ID and secret key for you to use.
For installations from source:
```yaml
- { name: 'gitlab', app_id: 'YOUR_APP_ID',
- { name: 'gitlab',
app_id: 'YOUR_APP_ID',
app_secret: 'YOUR_APP_SECRET',
args: { scope: 'api' } }
```

View file

@ -84,7 +84,8 @@ On your GitLab server:
For installations from source:
```yaml
- { name: 'google_oauth2', app_id: 'YOUR_APP_ID',
- { name: 'google_oauth2',
app_id: 'YOUR_APP_ID',
app_secret: 'YOUR_APP_SECRET',
args: { access_type: 'offline', approval_prompt: '' } }
```

View file

@ -207,6 +207,7 @@ remove the OmniAuth provider named `kerberos` from your `gitlab.yml` /
```yaml
omniauth:
# Rest of configuration omitted
# ...
providers:
- { name: 'kerberos' } # <-- remove this line

View file

@ -142,7 +142,7 @@ The chosen OmniAuth provider is now active and can be used to sign in to GitLab
## Automatically Link Existing Users to OmniAuth Users
> [Introduced in GitLab 13.4.](https://gitlab.com/gitlab-org/gitlab/-/merge_requests/36664)
> [Introduced](https://gitlab.com/gitlab-org/gitlab/-/merge_requests/36664) in GitLab 13.4.
You can automatically link OmniAuth users with existing GitLab users if their email addresses match.
For example, the following setting is used to enable the auto link feature for both a SAML provider and the Twitter OAuth provider:

View file

@ -65,7 +65,8 @@ To enable the Twitter OmniAuth provider you must register your application with
For installations from source:
```yaml
- { name: 'twitter', app_id: 'YOUR_APP_ID',
- { name: 'twitter',
app_id: 'YOUR_APP_ID',
app_secret: 'YOUR_APP_SECRET' }
```

View file

@ -70,7 +70,8 @@ receivers:
bearer_token: 9e1cbfcd546896a9ea8be557caf13a76
send_resolved: true
url: http://192.168.178.31:3001/root/manual_prometheus/prometheus/alerts/notify.json
...
# Rest of configuration omitted
# ...
```
For GitLab to associate your alerts with an [environment](../../ci/environments/index.md),

View file

@ -125,7 +125,7 @@ the Agent in subsequent steps. You can create an Agent record either:
- Through GraphQL: **(PREMIUM ONLY)**
```json
```graphql
mutation createAgent {
createClusterAgent(input: { projectPath: "path-to/your-awesome-project", name: "<agent-name>" }) {
clusterAgent {

View file

@ -269,7 +269,7 @@ To add a Kubernetes cluster to your project, group, or instance:
Copy the `<authentication_token>` value from the output:
```yaml
```plaintext
Name: gitlab-token-b5zv4
Namespace: kube-system
Labels: <none>

View file

@ -222,7 +222,8 @@ the environment of the deployed function:
```yaml
provider:
...
# Other configuration omitted
# ...
environment:
A_VARIABLE: ${env:A_VARIABLE}
```

View file

@ -92,10 +92,6 @@ module Gitlab
@version ||= database_version.match(/\A(?:PostgreSQL |)([^\s]+).*\z/)[1]
end
def self.postgresql_9_or_less?
version.to_f < 10
end
def self.postgresql_minimum_supported_version?
version.to_f >= MINIMUM_POSTGRES_VERSION
end
@ -127,28 +123,6 @@ module Gitlab
# ignore - happens when Rake tasks yet have to create a database, e.g. for testing
end
# map some of the function names that changed between PostgreSQL 9 and 10
# https://wiki.postgresql.org/wiki/New_in_postgres_10
def self.pg_wal_lsn_diff
Gitlab::Database.postgresql_9_or_less? ? 'pg_xlog_location_diff' : 'pg_wal_lsn_diff'
end
def self.pg_current_wal_insert_lsn
Gitlab::Database.postgresql_9_or_less? ? 'pg_current_xlog_insert_location' : 'pg_current_wal_insert_lsn'
end
def self.pg_last_wal_receive_lsn
Gitlab::Database.postgresql_9_or_less? ? 'pg_last_xlog_receive_location' : 'pg_last_wal_receive_lsn'
end
def self.pg_last_wal_replay_lsn
Gitlab::Database.postgresql_9_or_less? ? 'pg_last_xlog_replay_location' : 'pg_last_wal_replay_lsn'
end
def self.pg_last_xact_replay_timestamp
'pg_last_xact_replay_timestamp'
end
def self.nulls_last_order(field, direction = 'ASC')
Arel.sql("#{field} #{direction} NULLS LAST")
end

View file

@ -2686,6 +2686,9 @@ msgstr ""
msgid "An error has occurred"
msgstr ""
msgid "An error occured while making the changes: %{error}"
msgstr ""
msgid "An error occurred adding a draft to the thread."
msgstr ""
@ -2959,9 +2962,6 @@ msgstr ""
msgid "An error occurred while saving assignees"
msgstr ""
msgid "An error occurred while saving the template. Please check if the template exists."
msgstr ""
msgid "An error occurred while searching for milestones"
msgstr ""
@ -9527,6 +9527,9 @@ msgstr ""
msgid "Emails sent from Service Desk will have this name"
msgstr ""
msgid "Emails sent to %{email} will still be supported"
msgstr ""
msgid "Emails separated by comma"
msgstr ""

View file

@ -48,7 +48,10 @@ describe('AddIssuableForm', () => {
const input = findFormInput(wrapper);
if (input) input.blur();
if (wrapper) {
wrapper.destroy();
wrapper = null;
}
});
describe('with data', () => {

View file

@ -1,241 +1,146 @@
import Vue from 'vue';
import { shallowMount } from '@vue/test-utils';
import { PathIdSeparator } from '~/related_issues/constants';
import issueToken from '~/related_issues/components/issue_token.vue';
import IssueToken from '~/related_issues/components/issue_token.vue';
describe('IssueToken', () => {
const idKey = 200;
const displayReference = 'foo/bar#123';
const title = 'some title';
const pathIdSeparator = PathIdSeparator.Issue;
const eventNamespace = 'pendingIssuable';
let IssueToken;
let vm;
const path = '/foo/bar/issues/123';
const pathIdSeparator = PathIdSeparator.Issue;
const title = 'some title';
beforeEach(() => {
IssueToken = Vue.extend(issueToken);
let wrapper;
const defaultProps = {
idKey,
displayReference,
pathIdSeparator,
};
const createComponent = (props = {}) => {
wrapper = shallowMount(IssueToken, {
propsData: { ...defaultProps, ...props },
});
};
afterEach(() => {
if (vm) {
vm.$destroy();
if (wrapper) {
wrapper.destroy();
wrapper = null;
}
});
const findLink = () => wrapper.find({ ref: 'link' });
const findReference = () => wrapper.find({ ref: 'reference' });
const findReferenceIcon = () => wrapper.find('[data-testid="referenceIcon"]');
const findRemoveBtn = () => wrapper.find('[data-testid="removeBtn"]');
const findTitle = () => wrapper.find({ ref: 'title' });
describe('with reference supplied', () => {
beforeEach(() => {
vm = new IssueToken({
propsData: {
idKey,
eventNamespace,
displayReference,
pathIdSeparator,
},
}).$mount();
createComponent();
});
it('shows reference', () => {
expect(vm.$el.textContent.trim()).toEqual(displayReference);
expect(wrapper.text()).toContain(displayReference);
});
it('does not link without path specified', () => {
expect(vm.$refs.link.tagName.toLowerCase()).toEqual('span');
expect(vm.$refs.link.getAttribute('href')).toBeNull();
expect(findLink().element.tagName).toBe('SPAN');
expect(findLink().attributes('href')).toBeUndefined();
});
});
describe('with reference and title supplied', () => {
beforeEach(() => {
vm = new IssueToken({
propsData: {
idKey,
eventNamespace,
displayReference,
pathIdSeparator,
title,
},
}).$mount();
});
it('shows reference and title', () => {
expect(vm.$refs.reference.textContent.trim()).toEqual(displayReference);
expect(vm.$refs.title.textContent.trim()).toEqual(title);
});
});
describe('with path supplied', () => {
const path = '/foo/bar/issues/123';
beforeEach(() => {
vm = new IssueToken({
propsData: {
idKey,
eventNamespace,
displayReference,
pathIdSeparator,
createComponent({
title,
path,
},
}).$mount();
});
expect(findReference().text()).toBe(displayReference);
expect(findTitle().text()).toBe(title);
});
});
describe('with path and title supplied', () => {
it('links reference and title', () => {
expect(vm.$refs.link.getAttribute('href')).toEqual(path);
createComponent({
path,
title,
});
expect(findLink().attributes('href')).toBe(path);
});
});
describe('with state supplied', () => {
describe("`state: 'opened'`", () => {
beforeEach(() => {
vm = new IssueToken({
propsData: {
idKey,
eventNamespace,
displayReference,
pathIdSeparator,
state: 'opened',
},
}).$mount();
it.each`
state | icon | cssClass
${'opened'} | ${'issue-open-m'} | ${'issue-token-state-icon-open'}
${'reopened'} | ${'issue-open-m'} | ${'issue-token-state-icon-open'}
${'closed'} | ${'issue-close'} | ${'issue-token-state-icon-closed'}
`('shows "$icon" icon when "$state"', ({ state, icon, cssClass }) => {
createComponent({
path,
state,
});
it('shows green circle icon', () => {
expect(vm.$el.querySelector('.issue-token-state-icon-open.fa.fa-circle-o')).toBeDefined();
});
});
describe("`state: 'reopened'`", () => {
beforeEach(() => {
vm = new IssueToken({
propsData: {
idKey,
eventNamespace,
displayReference,
pathIdSeparator,
state: 'reopened',
},
}).$mount();
});
it('shows green circle icon', () => {
expect(vm.$el.querySelector('.issue-token-state-icon-open.fa.fa-circle-o')).toBeDefined();
});
});
describe("`state: 'closed'`", () => {
beforeEach(() => {
vm = new IssueToken({
propsData: {
idKey,
eventNamespace,
displayReference,
pathIdSeparator,
state: 'closed',
},
}).$mount();
});
it('shows red minus icon', () => {
expect(vm.$el.querySelector('.issue-token-state-icon-closed.fa.fa-minus')).toBeDefined();
});
expect(findReferenceIcon().props('name')).toBe(icon);
expect(findReferenceIcon().classes()).toContain(cssClass);
});
});
describe('with reference, title, state', () => {
const state = 'opened';
beforeEach(() => {
vm = new IssueToken({
propsData: {
idKey,
eventNamespace,
displayReference,
pathIdSeparator,
title,
state,
},
}).$mount();
});
it('shows reference, title, and state', () => {
const stateIcon = vm.$refs.reference.querySelector('svg');
createComponent({
title,
state,
});
expect(stateIcon.getAttribute('aria-label')).toEqual(state);
expect(vm.$refs.reference.textContent.trim()).toEqual(displayReference);
expect(vm.$refs.title.textContent.trim()).toEqual(title);
expect(findReferenceIcon().attributes('aria-label')).toBe(state);
expect(findReference().text()).toBe(displayReference);
expect(findTitle().text()).toBe(title);
});
});
describe('with canRemove', () => {
describe('`canRemove: false` (default)', () => {
beforeEach(() => {
vm = new IssueToken({
propsData: {
idKey,
eventNamespace,
displayReference,
pathIdSeparator,
},
}).$mount();
});
it('does not have remove button', () => {
expect(vm.$el.querySelector('.issue-token-remove-button')).toBeNull();
createComponent();
expect(findRemoveBtn().exists()).toBe(false);
});
});
describe('`canRemove: true`', () => {
beforeEach(() => {
vm = new IssueToken({
propsData: {
idKey,
createComponent({
eventNamespace,
displayReference,
pathIdSeparator,
canRemove: true,
},
}).$mount();
});
});
it('has remove button', () => {
expect(vm.$el.querySelector('.issue-token-remove-button')).toBeDefined();
});
});
expect(findRemoveBtn().exists()).toBe(true);
});
describe('methods', () => {
beforeEach(() => {
vm = new IssueToken({
propsData: {
idKey,
eventNamespace,
displayReference,
pathIdSeparator,
},
}).$mount();
it('emits event when clicked', () => {
findRemoveBtn().trigger('click');
const emitted = wrapper.emitted(`${eventNamespace}RemoveRequest`);
expect(emitted).toHaveLength(1);
expect(emitted[0]).toEqual([idKey]);
});
it('when getting checked', () => {
jest.spyOn(vm, '$emit').mockImplementation(() => {});
vm.onRemoveRequest();
expect(vm.$emit).toHaveBeenCalledWith('pendingIssuableRemoveRequest', vm.idKey);
it('tooltip should not be escaped', () => {
expect(findRemoveBtn().attributes('data-original-title')).toBe(
`Remove ${displayReference}`,
);
});
});
describe('tooltip', () => {
beforeEach(() => {
vm = new IssueToken({
propsData: {
idKey,
eventNamespace,
displayReference,
pathIdSeparator,
canRemove: true,
},
}).$mount();
});
it('should not be escaped', () => {
const { originalTitle } = vm.$refs.removeButton.dataset;
expect(originalTitle).toEqual(`Remove ${displayReference}`);
});
});
});

View file

@ -18,7 +18,10 @@ describe('RelatedIssuesBlock', () => {
const findIssueCountBadgeAddButton = () => wrapper.find(GlButton);
afterEach(() => {
if (wrapper) {
wrapper.destroy();
wrapper = null;
}
});
describe('with defaults', () => {

View file

@ -14,7 +14,10 @@ describe('RelatedIssuesList', () => {
let wrapper;
afterEach(() => {
if (wrapper) {
wrapper.destroy();
wrapper = null;
}
});
describe('with defaults', () => {

View file

@ -218,9 +218,7 @@ describe('ServiceDeskRoot', () => {
.$nextTick()
.then(waitForPromises)
.then(() => {
expect(wrapper.html()).toContain(
'An error occurred while saving the template. Please check if the template exists.',
);
expect(wrapper.html()).toContain('An error occured while making the changes:');
});
});
});

View file

@ -70,25 +70,6 @@ RSpec.describe Gitlab::Database do
end
end
describe '.postgresql_9_or_less?' do
it 'returns true when using postgresql 8.4' do
allow(described_class).to receive(:version).and_return('8.4')
expect(described_class.postgresql_9_or_less?).to eq(true)
end
it 'returns true when using PostgreSQL 9.6' do
allow(described_class).to receive(:version).and_return('9.6')
expect(described_class.postgresql_9_or_less?).to eq(true)
end
it 'returns false when using PostgreSQL 10 or newer' do
allow(described_class).to receive(:version).and_return('10')
expect(described_class.postgresql_9_or_less?).to eq(false)
end
end
describe '.postgresql_minimum_supported_version?' do
it 'returns false when using PostgreSQL 10' do
allow(described_class).to receive(:version).and_return('10')
@ -150,68 +131,6 @@ RSpec.describe Gitlab::Database do
end
end
describe '.pg_wal_lsn_diff' do
it 'returns old name when using PostgreSQL 9.6' do
allow(described_class).to receive(:version).and_return('9.6')
expect(described_class.pg_wal_lsn_diff).to eq('pg_xlog_location_diff')
end
it 'returns new name when using PostgreSQL 10 or newer' do
allow(described_class).to receive(:version).and_return('10')
expect(described_class.pg_wal_lsn_diff).to eq('pg_wal_lsn_diff')
end
end
describe '.pg_current_wal_insert_lsn' do
it 'returns old name when using PostgreSQL 9.6' do
allow(described_class).to receive(:version).and_return('9.6')
expect(described_class.pg_current_wal_insert_lsn).to eq('pg_current_xlog_insert_location')
end
it 'returns new name when using PostgreSQL 10 or newer' do
allow(described_class).to receive(:version).and_return('10')
expect(described_class.pg_current_wal_insert_lsn).to eq('pg_current_wal_insert_lsn')
end
end
describe '.pg_last_wal_receive_lsn' do
it 'returns old name when using PostgreSQL 9.6' do
allow(described_class).to receive(:version).and_return('9.6')
expect(described_class.pg_last_wal_receive_lsn).to eq('pg_last_xlog_receive_location')
end
it 'returns new name when using PostgreSQL 10 or newer' do
allow(described_class).to receive(:version).and_return('10')
expect(described_class.pg_last_wal_receive_lsn).to eq('pg_last_wal_receive_lsn')
end
end
describe '.pg_last_wal_replay_lsn' do
it 'returns old name when using PostgreSQL 9.6' do
allow(described_class).to receive(:version).and_return('9.6')
expect(described_class.pg_last_wal_replay_lsn).to eq('pg_last_xlog_replay_location')
end
it 'returns new name when using PostgreSQL 10 or newer' do
allow(described_class).to receive(:version).and_return('10')
expect(described_class.pg_last_wal_replay_lsn).to eq('pg_last_wal_replay_lsn')
end
end
describe '.pg_last_xact_replay_timestamp' do
it 'returns pg_last_xact_replay_timestamp' do
expect(described_class.pg_last_xact_replay_timestamp).to eq('pg_last_xact_replay_timestamp')
end
end
describe '.nulls_last_order' do
it { expect(described_class.nulls_last_order('column', 'ASC')).to eq 'column ASC NULLS LAST'}
it { expect(described_class.nulls_last_order('column', 'DESC')).to eq 'column DESC NULLS LAST'}