initial commit
This commit is contained in:
Коммит
020e4f7f91
|
@ -0,0 +1,20 @@
|
|||
The MIT License (MIT)
|
||||
Copyright (c) Microsoft Corporation
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
of this software and associated documentation files (the "Software"), to deal
|
||||
in the Software without restriction, including without limitation the rights
|
||||
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
copies of the Software, and to permit persons to whom the Software is
|
||||
furnished to do so, subject to the following conditions:
|
||||
|
||||
The above copyright notice and this permission notice shall be included in all
|
||||
copies or substantial portions of the Software.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||
SOFTWARE.
|
|
@ -0,0 +1 @@
|
|||
# test-cloud-espresso-extensions
|
|
@ -0,0 +1,96 @@
|
|||
buildscript {
|
||||
repositories {
|
||||
jcenter()
|
||||
}
|
||||
dependencies {
|
||||
classpath 'com.android.tools.build:gradle:2.2.1'
|
||||
}
|
||||
}
|
||||
|
||||
apply plugin: 'com.android.library'
|
||||
|
||||
android {
|
||||
compileSdkVersion 23
|
||||
buildToolsVersion "23.0.2"
|
||||
|
||||
defaultConfig {
|
||||
minSdkVersion 9
|
||||
targetSdkVersion 23
|
||||
versionCode 1
|
||||
versionName "1.0"
|
||||
|
||||
testInstrumentationRunner "android.support.test.runner.AndroidJUnitRunner"
|
||||
|
||||
}
|
||||
buildTypes {
|
||||
release {
|
||||
minifyEnabled false
|
||||
proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro'
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
repositories {
|
||||
mavenLocal()
|
||||
jcenter()
|
||||
}
|
||||
|
||||
apply plugin: 'maven-publish'
|
||||
|
||||
task preparePublish(dependsOn: build)
|
||||
|
||||
publishing {
|
||||
publications {
|
||||
androidLib(MavenPublication) {
|
||||
artifact "build/outputs/aar/test-cloud-espresso-extensions-release.aar"
|
||||
groupId "com.xamarin.testcloud"
|
||||
artifactId "espresso-support"
|
||||
version "1.0-SNAPSHOT"
|
||||
|
||||
pom.withXml {
|
||||
asNode().children().last() + {
|
||||
resolveStrategy = Closure.DELEGATE_FIRST
|
||||
name 'Xamarin Test cloud espresso extensions'
|
||||
description 'Extensions for producing nice looking test reports for espresso tests in Xamarin Test Cloud'
|
||||
url 'http://testcloud.xamarin.com'
|
||||
scm {
|
||||
connection 'scm:git:git@github.com:xamarinhq/test-cloud-appium-espresso-extensions.git'
|
||||
developerConnection 'scm:git:git@github.com:xamarinhq/test-cloud-appium-espresso-extensions.git'
|
||||
url 'git@github.com:xamarinhq/test-cloud-appium-espresso-extensions.git'
|
||||
}
|
||||
licenses {
|
||||
license {
|
||||
name 'MIT License'
|
||||
url 'http://www.opensource.org/licenses/mit-license.php'
|
||||
}
|
||||
}
|
||||
developers {
|
||||
developer {
|
||||
name 'Chris Fuentes'
|
||||
email 'chris.fuentes@xamarin.com'
|
||||
organization 'Xamarin'
|
||||
organizationUrl 'http://www.xamarin.com'
|
||||
}
|
||||
developer {
|
||||
name 'Simon Søndergaard'
|
||||
email 'simon@xamarin.com'
|
||||
organization 'Xamarin'
|
||||
organizationUrl 'http://www.xamarin.com'
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
dependencies {
|
||||
androidTestCompile('com.android.support.test.espresso:espresso-core:2.2.2', {
|
||||
exclude group: 'com.android.support', module: 'support-annotations'
|
||||
})
|
||||
compile 'com.xamarin.testcloud:event:1.0-SNAPSHOT', {
|
||||
exclude group: 'junit', module: 'junit'
|
||||
}
|
||||
compile group: 'com.google.code.gson', name: 'gson', version: '2.7'
|
||||
provided 'com.android.support.test:runner:0.5'
|
||||
}
|
|
@ -0,0 +1,17 @@
|
|||
# Add project specific ProGuard rules here.
|
||||
# By default, the flags in this file are appended to flags specified
|
||||
# in /Tools/android-sdk-macosx/tools/proguard/proguard-android.txt
|
||||
# You can edit the include path and order by changing the proguardFiles
|
||||
# directive in build.gradle.
|
||||
#
|
||||
# For more details, see
|
||||
# http://developer.android.com/guide/developing/tools/proguard.html
|
||||
|
||||
# Add any project specific keep options here:
|
||||
|
||||
# If your project uses WebView with JS, uncomment the following
|
||||
# and specify the fully qualified class name to the JavaScript interface
|
||||
# class:
|
||||
#-keepclassmembers class fqcn.of.javascript.interface.for.webview {
|
||||
# public *;
|
||||
#}
|
|
@ -0,0 +1,43 @@
|
|||
package com.xamarin.testcloud.espresso;
|
||||
|
||||
import android.net.LocalServerSocket;
|
||||
|
||||
import com.xamarin.testcloud.event.Event;
|
||||
import com.xamarin.testcloud.event.EventType;
|
||||
|
||||
import org.junit.Before;
|
||||
import org.junit.BeforeClass;
|
||||
import org.junit.Test;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.util.concurrent.TimeUnit;
|
||||
|
||||
import static org.junit.Assert.*;
|
||||
|
||||
public class EventServerTest {
|
||||
@Test
|
||||
public void sendSync_will_return_false_if_no_one_listens() throws Exception {
|
||||
String socketName = "junitevent";
|
||||
LocalServerSocket socket = new LocalServerSocket(socketName);
|
||||
EventServer server = new EventServer(socket, 10, TimeUnit.MILLISECONDS);
|
||||
|
||||
boolean b = server.sendSync(Event.create("id", EventType.started, "testName", "className", 1));
|
||||
server.stop();
|
||||
|
||||
assertFalse("sendSync without a listener should return false", b);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void sendSync_will_return_true_if_some_one_listens() throws Exception {
|
||||
String socketName = "junitevent2";
|
||||
LocalServerSocket socket = new LocalServerSocket(socketName);
|
||||
EventServer server = new EventServer(socket, 10, TimeUnit.SECONDS);
|
||||
TestEventClient client = new TestEventClient(socketName);
|
||||
|
||||
boolean b = server.sendSync(Event.create("id", EventType.started, "testName", "className", 1));
|
||||
server.stop();
|
||||
client.stop();
|
||||
|
||||
assertTrue("sendSync with a listener should return true", b);
|
||||
}
|
||||
}
|
|
@ -0,0 +1,59 @@
|
|||
package com.xamarin.testcloud.espresso;
|
||||
|
||||
import android.net.LocalSocket;
|
||||
import android.net.LocalSocketAddress;
|
||||
|
||||
import java.io.BufferedWriter;
|
||||
import java.io.IOException;
|
||||
import java.io.InputStreamReader;
|
||||
import java.io.OutputStreamWriter;
|
||||
import java.util.concurrent.ExecutorService;
|
||||
import java.util.concurrent.Executors;
|
||||
import java.util.concurrent.Future;
|
||||
|
||||
public class TestEventClient implements Runnable {
|
||||
private final String name;
|
||||
|
||||
private final ExecutorService executorService = Executors.newSingleThreadExecutor();
|
||||
private final Future<?> task;
|
||||
|
||||
public TestEventClient(String name) {
|
||||
this.name = name;
|
||||
this.task = executorService.submit(this);
|
||||
}
|
||||
|
||||
public void stop() {
|
||||
boolean cancel = task.cancel(true);
|
||||
executorService.shutdownNow();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void run() {
|
||||
while (!Thread.interrupted()) {
|
||||
LocalSocket socket = null;
|
||||
try {
|
||||
socket = new LocalSocket();
|
||||
socket.connect(new LocalSocketAddress(name));
|
||||
|
||||
BufferedWriter bufferedWriter = new BufferedWriter(new OutputStreamWriter(socket.getOutputStream()));
|
||||
InputStreamReader inputStreamReader = new InputStreamReader(socket.getInputStream());
|
||||
|
||||
while (true) {
|
||||
String line = EventServer.readLine(inputStreamReader);
|
||||
bufferedWriter.write("ok\n");
|
||||
bufferedWriter.flush();
|
||||
}
|
||||
} catch (IOException e) {
|
||||
e.printStackTrace();
|
||||
} finally {
|
||||
if (socket != null) {
|
||||
try {
|
||||
socket.close();
|
||||
} catch (IOException e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,9 @@
|
|||
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
package="com.xamarin.testcloud.espresso">
|
||||
|
||||
<application android:allowBackup="true" android:label="@string/app_name"
|
||||
android:supportsRtl="true">
|
||||
|
||||
</application>
|
||||
|
||||
</manifest>
|
|
@ -0,0 +1,144 @@
|
|||
package com.xamarin.testcloud.espresso;
|
||||
|
||||
import android.net.LocalServerSocket;
|
||||
import android.net.LocalSocket;
|
||||
|
||||
import com.google.gson.Gson;
|
||||
import com.xamarin.testcloud.event.Event;
|
||||
|
||||
import java.io.BufferedWriter;
|
||||
import java.io.IOException;
|
||||
import java.io.InputStreamReader;
|
||||
import java.io.OutputStreamWriter;
|
||||
import java.io.Reader;
|
||||
import java.util.concurrent.ExecutorService;
|
||||
import java.util.concurrent.Executors;
|
||||
import java.util.concurrent.Future;
|
||||
import java.util.concurrent.SynchronousQueue;
|
||||
import java.util.concurrent.TimeUnit;
|
||||
import java.util.concurrent.locks.Condition;
|
||||
import java.util.concurrent.locks.Lock;
|
||||
import java.util.concurrent.locks.ReentrantLock;
|
||||
|
||||
public class EventServer implements Runnable {
|
||||
private final LocalServerSocket socket;
|
||||
private final SynchronousQueue<String> queue = new SynchronousQueue<String>();
|
||||
|
||||
private final Lock sendStatusLock = new ReentrantLock();
|
||||
private final Condition sendStatusSet = sendStatusLock.newCondition();
|
||||
private final int timeout;
|
||||
private final TimeUnit unit;
|
||||
private Boolean successfulAck = null; // Guarded by sendStatusLock
|
||||
|
||||
private final ExecutorService executorService = Executors.newSingleThreadExecutor();
|
||||
private final Future<?> serverTask;
|
||||
|
||||
private final Gson gson = new Gson();
|
||||
|
||||
public EventServer(LocalServerSocket socket) {
|
||||
this(socket, 10, TimeUnit.SECONDS);
|
||||
}
|
||||
|
||||
// For testing
|
||||
EventServer(LocalServerSocket socket, int timeout, TimeUnit unit) {
|
||||
this.socket = socket;
|
||||
serverTask = executorService.submit(this);
|
||||
this.timeout = timeout;
|
||||
this.unit = unit;
|
||||
}
|
||||
|
||||
static String readLine(Reader reader) throws IOException {
|
||||
StringBuilder builder = new StringBuilder();
|
||||
do {
|
||||
int c = reader.read();
|
||||
if(c == -1 || c == '\n') {
|
||||
break;
|
||||
}
|
||||
builder.append((char)c);
|
||||
} while (true);
|
||||
return builder.toString();
|
||||
}
|
||||
|
||||
public boolean sendSync(Event event) {
|
||||
String asjson = gson.toJson(event);
|
||||
try {
|
||||
boolean wasAccepted = queue.offer(asjson, timeout, unit);
|
||||
if (!wasAccepted) {
|
||||
return false;
|
||||
}
|
||||
|
||||
if (sendStatusLock.tryLock(timeout, unit)) {
|
||||
try {
|
||||
while (successfulAck == null) {
|
||||
boolean statusInTime = sendStatusSet.await(timeout, unit);
|
||||
if (!statusInTime) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
return successfulAck;
|
||||
} finally {
|
||||
successfulAck = null;
|
||||
sendStatusLock.unlock();
|
||||
}
|
||||
}
|
||||
} catch (InterruptedException e) {
|
||||
// Ignored
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
public void stop() throws InterruptedException {
|
||||
boolean cancel = serverTask.cancel(true);
|
||||
executorService.shutdownNow();
|
||||
try {
|
||||
socket.close();
|
||||
} catch (IOException e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void run() {
|
||||
while (!Thread.interrupted()) {
|
||||
LocalSocket accept = null;
|
||||
try {
|
||||
accept = socket.accept();
|
||||
|
||||
InputStreamReader reader = new InputStreamReader(accept.getInputStream());
|
||||
BufferedWriter bufferedWriter = new BufferedWriter(new OutputStreamWriter(accept.getOutputStream()));
|
||||
|
||||
boolean ackOK = false;
|
||||
do {
|
||||
String string = queue.take();
|
||||
try {
|
||||
bufferedWriter.write(string);
|
||||
bufferedWriter.newLine();
|
||||
bufferedWriter.flush();
|
||||
String status = readLine(reader);
|
||||
ackOK = "ok".equals(status);
|
||||
} finally {
|
||||
sendStatusLock.lock();
|
||||
try {
|
||||
successfulAck = ackOK;
|
||||
sendStatusSet.signal();
|
||||
} finally {
|
||||
sendStatusLock.unlock();
|
||||
}
|
||||
}
|
||||
} while (ackOK);
|
||||
} catch (IOException e) {
|
||||
e.printStackTrace();
|
||||
} catch (InterruptedException e) {
|
||||
e.printStackTrace();
|
||||
} finally {
|
||||
if (accept != null) {
|
||||
try {
|
||||
accept.close();
|
||||
} catch (IOException e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,25 @@
|
|||
package com.xamarin.testcloud.espresso;
|
||||
|
||||
import android.support.test.InstrumentationRegistry;
|
||||
|
||||
import com.xamarin.testcloud.event.StdOutEventReporter;
|
||||
|
||||
public class Factory {
|
||||
private static RapportHelper rapportHelper;
|
||||
|
||||
static {
|
||||
String label = InstrumentationRegistry.getArguments().getString("label");
|
||||
if ("true".equals(label)) {
|
||||
rapportHelper = new RapportHelper(new LocalSocketEventReporter("junitevent"));
|
||||
} else {
|
||||
rapportHelper = new RapportHelper(new StdOutEventReporter());
|
||||
}
|
||||
}
|
||||
|
||||
public static RapportHelper getRapportHelper() {
|
||||
return rapportHelper;
|
||||
}
|
||||
|
||||
private Factory() {
|
||||
}
|
||||
}
|
|
@ -0,0 +1,29 @@
|
|||
package com.xamarin.testcloud.espresso;
|
||||
|
||||
import android.net.LocalServerSocket;
|
||||
|
||||
import com.xamarin.testcloud.event.Event;
|
||||
import com.xamarin.testcloud.event.EventReporter;
|
||||
|
||||
import java.io.IOException;
|
||||
|
||||
public class LocalSocketEventReporter extends EventReporter {
|
||||
private final EventServer server;
|
||||
|
||||
public LocalSocketEventReporter(String socketName) {
|
||||
EventServer server1;
|
||||
try {
|
||||
LocalServerSocket socket = new LocalServerSocket(socketName);
|
||||
server1 = new EventServer(socket);
|
||||
} catch (IOException e) {
|
||||
server1 = null;
|
||||
new RuntimeException("Unable to create server socket");
|
||||
}
|
||||
this.server = server1;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void commit(Event event) throws IOException {
|
||||
boolean b = server.sendSync(event);
|
||||
}
|
||||
}
|
|
@ -0,0 +1,49 @@
|
|||
package com.xamarin.testcloud.espresso;
|
||||
|
||||
import com.xamarin.testcloud.event.EventReporter;
|
||||
import com.xamarin.testcloud.event.EventType;
|
||||
import org.junit.rules.TestWatcher;
|
||||
import org.junit.runner.Description;
|
||||
|
||||
public class RapportHelper extends TestWatcher {
|
||||
private final EventReporter eventReporter;
|
||||
|
||||
RapportHelper(EventReporter eventReporter) {
|
||||
super();
|
||||
this.eventReporter = eventReporter;
|
||||
}
|
||||
|
||||
public void label(String label) {
|
||||
this.eventReporter.reportLabel(label, "NA", -1, false);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void succeeded(Description description) {
|
||||
super.succeeded(description);
|
||||
this.eventReporter.reportJunit(EventType.succeeded, description, null);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void failed(Throwable e, Description description) {
|
||||
this.eventReporter.reportJunit(EventType.failed, description, e);
|
||||
super.failed(e, description);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void skipped(org.junit.internal.AssumptionViolatedException e, Description description) {
|
||||
this.eventReporter.reportJunit(EventType.skipped, description, e);
|
||||
super.skipped(e, description);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void starting(Description description) {
|
||||
super.starting(description);
|
||||
this.eventReporter.reportJunit(EventType.started, description, null);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void finished(Description description) {
|
||||
super.finished(description);
|
||||
this.eventReporter.reportJunit(EventType.finished, description, null);
|
||||
}
|
||||
}
|
|
@ -0,0 +1,3 @@
|
|||
<resources>
|
||||
<string name="app_name">ESLibrary</string>
|
||||
</resources>
|
Загрузка…
Ссылка в новой задаче