Skip to content

Commit

Permalink
basic testing in place
Browse files Browse the repository at this point in the history
  • Loading branch information
therealryan committed Aug 13, 2024
1 parent 1b2a63b commit a9731b6
Show file tree
Hide file tree
Showing 8 changed files with 171 additions and 10 deletions.
3 changes: 2 additions & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@ github actions artifact proxy

# TODO

1. Tests
1. better browser control in testing - headless default, stepping, etc
1. GUI for local use
1. Wait for about 90 days for the artifact-link tests to fail, then fix them

Original file line number Diff line number Diff line change
Expand Up @@ -47,7 +47,7 @@ public void handle( HttpExchange exchange ) throws IOException {
Matcher artifactMatch = GITHUB_ARTIFACT_LINK.matcher( link );
if( artifactMatch.find() ) {
ServeUtil.redirect( exchange, String.format(
"/artifacts/%s/%s/%s",
"/artifacts/%s/%s/%s/",
artifactMatch.group( 1 ), artifactMatch.group( 2 ), artifactMatch.group( 3 ) ) );
return;
}
Expand Down
6 changes: 4 additions & 2 deletions model/src/main/java/dev/flowty/bowlby/model/BowlbySystem.java
Original file line number Diff line number Diff line change
Expand Up @@ -5,8 +5,9 @@
import com.mastercard.test.flow.Unpredictable;
import com.mastercard.test.flow.model.LazyModel;

import dev.flowty.bowlby.model.flow.ArtifactLink;
import dev.flowty.bowlby.model.flow.Index;
import dev.flowty.bowlby.model.flow.Latest;
import dev.flowty.bowlby.model.flow.LatestFromWorkflow;

/**
* Models the expected behaviour of the system
Expand Down Expand Up @@ -59,7 +60,8 @@ public enum Unpredictables implements Unpredictable {
*/
public static final Model MODEL = new LazyModel( "Bowlby" )
.with( Index.class )
.with( Latest.class )
.with( LatestFromWorkflow.class )
.with( ArtifactLink.class )

;
}
132 changes: 132 additions & 0 deletions model/src/main/java/dev/flowty/bowlby/model/flow/ArtifactLink.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,132 @@
package dev.flowty.bowlby.model.flow;

import com.mastercard.test.flow.Flow;
import com.mastercard.test.flow.builder.Chain;
import com.mastercard.test.flow.builder.Creator;
import com.mastercard.test.flow.builder.Deriver;
import com.mastercard.test.flow.model.EagerModel;
import com.mastercard.test.flow.util.TaggedGroup;
import com.mastercard.test.flow.util.Tags;

import dev.flowty.bowlby.model.BowlbySystem.Actors;
import dev.flowty.bowlby.model.msg.ApiMessage;
import dev.flowty.bowlby.model.msg.ArtifactMessage;
import dev.flowty.bowlby.model.msg.ArtifactMessage.Artifact;
import dev.flowty.bowlby.model.msg.HttpMessage;
import dev.flowty.bowlby.model.msg.WebMessage;
import dev.flowty.bowlby.model.msg.ntr.Interactions;

/**
* Flows that explore the browse-this-artifact behaviour
*/
public class ArtifactLink extends EagerModel {

/***/
public static final TaggedGroup MODEL_TAGS = new TaggedGroup( "chain:workflow" )
.union( "200", "303", "artifact" );

/***
* @param index provides the basis for our form retrieval
*/
public ArtifactLink( Index index ) {
super( MODEL_TAGS );

Chain chain = new Chain( "artifact" );

Flow get = Deriver.build( index.get,
flow -> flow
.meta( data -> data
.description( "form" )
.motivation(
"""
This chain demonstrates the ability to browse artifact files.
We start by visiting the bowlby root page, which offers a form that accepts links to github artifacts.""" ) )
.prerequisite( index.get )
.removeCall( Interactions.FAVICON ),
chain );

Flow submit = Creator.build( flow -> flow
.meta( data -> data
.description( "submit" )
.tags( Tags.add( "302", "200", "artifact" ) )
.motivation(
"""
Submitting an artifact link via the form.\
Bowbly will return a 302 redirect to the url at which the artifact can be browsed""" ) )
.prerequisite( get )
.call( a -> a
.from( Actors.USER )
.to( Actors.BROWSER )
.request( WebMessage.submit(
"https://github.com/therealryan/bowlby/actions/runs/10334399684/artifacts/1798279626" ) )
.call( b -> b.to( Actors.BOWLBY )
.tags( Tags.add( "submit" ) )
.request( HttpMessage.chromeRequest( "GET", ""
+ "/?link=https%3A%2F%2Fgit.luolix.top%2Ftherealryan%2Fbowlby%2Factions%2Fruns%2F10334399684%2Fartifacts%2F1798279626" ) )
.response( HttpMessage.redirectResponse(
"/artifacts/therealryan/bowlby/1798279626/" ) ) )
.call( b -> b.to( Actors.BOWLBY )
.tags( Tags.add( "download" ) )
.request( HttpMessage.chromeRequest( "GET",
"/artifacts/therealryan/bowlby/1798279626/" ) )
.call( c -> c.to( Actors.GITHUB )
.request( ApiMessage.request(
"/repos/therealryan/bowlby/actions/artifacts/1798279626/zip" ) )
.response( ApiMessage.artifactRedirect() ) )
.call( c -> c.to( Actors.ARTIFACTS )
.request( ArtifactMessage.get( "/a/very/long/url" ) )
.response( ArtifactMessage.data( Artifact.BETA ) ) )
.response( HttpMessage.directoryListing( "file.txt", "subdir/" ) ) )
.response( WebMessage.summarise()
.set( "forms", "" )
.set( "header", "[bowlby](http://[::]:56567/)" )
.set( "lists",
"""
[file.txt](http://[::]:56567/artifacts/therealryan/bowlby/1798279626/file.txt)
[subdir/](http://[::]:_masked_/artifacts/therealryan/bowlby/_masked_/subdir/)""" )
.set( "url", "http://[::]:56567/artifacts/therealryan/bowlby/1798279626/" ) ) ),
chain );

Flow dir = Creator.build( flow -> flow.meta( data -> data
.description( "dir" )
.motivation( "Clicking through to view the subdirectory" ) )
.prerequisite( submit )
.call( a -> a
.from( Actors.USER )
.to( Actors.BROWSER )
.request( WebMessage.clickLink( "subdir/" ) )
.call( b -> b.to( Actors.BOWLBY )
.request( HttpMessage.chromeRequest( "GET",
"/artifacts/therealryan/bowlby/1798279626/subdir/" ) )
.response( HttpMessage.directoryListing( "../", "subfile.txt" ) ) )
.response( WebMessage.summarise()
.set( "forms", "" )
.set( "header", "[bowlby](http://[::]:56567/)" )
.set( "lists",
"""
[../](http://[::]:56567/artifacts/therealryan/bowlby/1798279626/)
[subfile.txt](http://[::]:_masked_/artifacts/therealryan/bowlby/_masked_/subdir/subfile.txt)""" )
.set( "url",
"http://[::]:56567/artifacts/therealryan/bowlby/1798279626/subdir/" ) ) ),
chain );

Flow file = Creator.build( flow -> flow.meta( data -> data
.description( "file" )
.motivation( "Clicking through to view a file" ) )
.prerequisite( dir )
.call( a -> a
.from( Actors.USER )
.to( Actors.BROWSER )
.request( WebMessage.clickLink( "subfile.txt" ) )
.call( b -> b.to( Actors.BOWLBY )
.request( HttpMessage.chromeRequest( "GET",
"/artifacts/therealryan/bowlby/1798279626/subdir/subfile.txt" ) )
.response( HttpMessage.textResponse(
"This is just a text file in a subdirectory!\n" ) ) )
.response( WebMessage.text()
.set( "text", "This is just a text file in a subdirectory!" ) ) ),
chain );

members( flatten( get, submit, dir, file ) );
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -21,7 +21,7 @@
/**
* Flows that explore the get-latest-artifact behaviour
*/
public class Latest extends EagerModel {
public class LatestFromWorkflow extends EagerModel {

/***/
public static final TaggedGroup MODEL_TAGS = new TaggedGroup( "chain:workflow" )
Expand All @@ -30,7 +30,7 @@ public class Latest extends EagerModel {
/**
* @param index The source of the index-get flow
*/
public Latest( Index index ) {
public LatestFromWorkflow( Index index ) {
super( MODEL_TAGS );

Chain chain = new Chain( "workflow" );
Expand Down
20 changes: 20 additions & 0 deletions model/src/main/java/dev/flowty/bowlby/model/msg/HttpMessage.java
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@
import com.mastercard.test.flow.msg.http.HttpMsg;
import com.mastercard.test.flow.msg.http.HttpReq;
import com.mastercard.test.flow.msg.http.HttpRes;
import com.mastercard.test.flow.msg.txt.Text;
import com.mastercard.test.flow.msg.xml.XML;

import dev.flowty.bowlby.model.BowlbySystem.Unpredictables;
Expand Down Expand Up @@ -149,6 +150,25 @@ public static Message directoryListing( String... files ) {
return res;
}

/**
* Builds an artifact0content text response
*
* @param body The expected file content
* @return The 200 response message
*/
public static Message textResponse( String body ) {
return new HttpRes()
.set( HttpMsg.VERSION, "HTTP/1.1" )
.set( HttpRes.STATUS, 200 )
.set( HttpMsg.header( "cache-control" ), "max-age=31536000, immutable" )
.set( HttpMsg.header( "content-type" ), "text/plain" )
.set( HttpMsg.BODY, new Text( body ) )
.masking( Unpredictables.BORING, m -> m
.delete( Stream.of(
"content-length", "date" )
.map( HttpMsg::header ) ) );
}

/**
* Builds bowlby's icon response. Note that we're not bothering to model the
* icon content
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -93,6 +93,15 @@ public static Message summarise() {
"\\d{4}-\\d{2}-\\d{2}T\\d{2}:\\d{2}:\\d{2}.\\d+Z", "_masked_" ) ) );
}

/**
* @return extracts the page text
*/
public static Message text() {
return new WebSequence()
.operation( "dump text", ( driver, params ) -> params
.put( "text", driver.findElement( By.tagName( "html" ) ).getText() ) );
}

private static String summarise( WebDriver driver, String tag ) {
return driver.findElements( By.tagName( tag ) ).stream()
.map( e -> summarise( driver, e ) )
Expand Down
5 changes: 1 addition & 4 deletions test/src/test/java/dev/flowty/bowlby/it/ApiIT.java
Original file line number Diff line number Diff line change
Expand Up @@ -24,7 +24,6 @@

import dev.flowty.bowlby.model.BowlbySystem;
import dev.flowty.bowlby.test.HttpFlow;
import dev.flowty.bowlby.test.TestLog;

/**
* Exercises github in isolation
Expand Down Expand Up @@ -54,9 +53,7 @@ Stream<DynamicNode> tests() {
return new Flocessor( "github", BowlbySystem.MODEL )
.system( State.FUL, GITHUB )
.masking( BORING, RNG )
.logs( TestLog.TAIL )
// reports will leak the token!
.reporting( Reporting.NEVER, "github" )
.reporting( Reporting.ALWAYS, "github" )
.behaviour( asrt -> {
HttpReq request = (HttpReq) asrt.expected().request().child();

Expand Down

0 comments on commit a9731b6

Please sign in to comment.